@@ -94,6 +94,222 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
94
94
95
95
mlir::Value VisitUnaryExprOrTypeTraitExpr (const UnaryExprOrTypeTraitExpr *e);
96
96
97
+ // Unary Operators.
98
+ mlir::Value VisitUnaryPostDec (const UnaryOperator *e) {
99
+ LValue lv = cgf.emitLValue (e->getSubExpr ());
100
+ return emitScalarPrePostIncDec (e, lv, false , false );
101
+ }
102
+ mlir::Value VisitUnaryPostInc (const UnaryOperator *e) {
103
+ LValue lv = cgf.emitLValue (e->getSubExpr ());
104
+ return emitScalarPrePostIncDec (e, lv, true , false );
105
+ }
106
+ mlir::Value VisitUnaryPreDec (const UnaryOperator *e) {
107
+ LValue lv = cgf.emitLValue (e->getSubExpr ());
108
+ return emitScalarPrePostIncDec (e, lv, false , true );
109
+ }
110
+ mlir::Value VisitUnaryPreInc (const UnaryOperator *e) {
111
+ LValue lv = cgf.emitLValue (e->getSubExpr ());
112
+ return emitScalarPrePostIncDec (e, lv, true , true );
113
+ }
114
+ mlir::Value emitScalarPrePostIncDec (const UnaryOperator *e, LValue lv,
115
+ bool isInc, bool isPre) {
116
+ if (cgf.getLangOpts ().OpenMP )
117
+ cgf.cgm .errorNYI (e->getSourceRange (), " inc/dec OpenMP" );
118
+
119
+ QualType type = e->getSubExpr ()->getType ();
120
+
121
+ mlir::Value value;
122
+ mlir::Value input;
123
+
124
+ if (type->getAs <AtomicType>()) {
125
+ cgf.cgm .errorNYI (e->getSourceRange (), " Atomic inc/dec" );
126
+ // TODO(cir): This is not correct, but it will produce reasonable code
127
+ // until atomic operations are implemented.
128
+ value = cgf.emitLoadOfLValue (lv, e->getExprLoc ()).getScalarVal ();
129
+ input = value;
130
+ } else {
131
+ value = cgf.emitLoadOfLValue (lv, e->getExprLoc ()).getScalarVal ();
132
+ input = value;
133
+ }
134
+
135
+ // NOTE: When possible, more frequent cases are handled first.
136
+
137
+ // Special case of integer increment that we have to check first: bool++.
138
+ // Due to promotion rules, we get:
139
+ // bool++ -> bool = bool + 1
140
+ // -> bool = (int)bool + 1
141
+ // -> bool = ((int)bool + 1 != 0)
142
+ // An interesting aspect of this is that increment is always true.
143
+ // Decrement does not have this property.
144
+ if (isInc && type->isBooleanType ()) {
145
+ value = builder.create <cir::ConstantOp>(cgf.getLoc (e->getExprLoc ()),
146
+ cgf.convertType (type),
147
+ builder.getCIRBoolAttr (true ));
148
+ } else if (type->isIntegerType ()) {
149
+ QualType promotedType;
150
+ bool canPerformLossyDemotionCheck = false ;
151
+ if (cgf.getContext ().isPromotableIntegerType (type)) {
152
+ promotedType = cgf.getContext ().getPromotedIntegerType (type);
153
+ assert (promotedType != type && " Shouldn't promote to the same type." );
154
+ canPerformLossyDemotionCheck = true ;
155
+ canPerformLossyDemotionCheck &=
156
+ cgf.getContext ().getCanonicalType (type) !=
157
+ cgf.getContext ().getCanonicalType (promotedType);
158
+ canPerformLossyDemotionCheck &=
159
+ type->isIntegerType () && promotedType->isIntegerType ();
160
+
161
+ // TODO(cir): Currently, we store bitwidths in CIR types only for
162
+ // integers. This might also be required for other types.
163
+ auto srcCirTy = mlir::dyn_cast<cir::IntType>(cgf.convertType (type));
164
+ auto promotedCirTy =
165
+ mlir::dyn_cast<cir::IntType>(cgf.convertType (type));
166
+ assert (srcCirTy && promotedCirTy && " Expected integer type" );
167
+
168
+ assert (
169
+ (!canPerformLossyDemotionCheck ||
170
+ type->isSignedIntegerOrEnumerationType () ||
171
+ promotedType->isSignedIntegerOrEnumerationType () ||
172
+ srcCirTy.getWidth () == promotedCirTy.getWidth ()) &&
173
+ " The following check expects that if we do promotion to different "
174
+ " underlying canonical type, at least one of the types (either "
175
+ " base or promoted) will be signed, or the bitwidths will match." );
176
+ }
177
+
178
+ assert (!cir::MissingFeatures::sanitizers ());
179
+ if (e->canOverflow () && type->isSignedIntegerOrEnumerationType ()) {
180
+ value = emitIncDecConsiderOverflowBehavior (e, value, isInc);
181
+ } else {
182
+ cir::UnaryOpKind kind =
183
+ e->isIncrementOp () ? cir::UnaryOpKind::Inc : cir::UnaryOpKind::Dec;
184
+ // NOTE(CIR): clang calls CreateAdd but folds this to a unary op
185
+ value = emitUnaryOp (e, kind, input);
186
+ }
187
+ } else if (const PointerType *ptr = type->getAs <PointerType>()) {
188
+ cgf.cgm .errorNYI (e->getSourceRange (), " Unary inc/dec pointer" );
189
+ return {};
190
+ } else if (type->isVectorType ()) {
191
+ cgf.cgm .errorNYI (e->getSourceRange (), " Unary inc/dec vector" );
192
+ return {};
193
+ } else if (type->isRealFloatingType ()) {
194
+ assert (!cir::MissingFeatures::CGFPOptionsRAII ());
195
+
196
+ if (type->isHalfType () &&
197
+ !cgf.getContext ().getLangOpts ().NativeHalfType ) {
198
+ cgf.cgm .errorNYI (e->getSourceRange (), " Unary inc/dec half" );
199
+ return {};
200
+ }
201
+
202
+ if (mlir::isa<cir::SingleType, cir::DoubleType>(value.getType ())) {
203
+ // Create the inc/dec operation.
204
+ // NOTE(CIR): clang calls CreateAdd but folds this to a unary op
205
+ cir::UnaryOpKind kind =
206
+ (isInc ? cir::UnaryOpKind::Inc : cir::UnaryOpKind::Dec);
207
+ value = emitUnaryOp (e, kind, value);
208
+ } else {
209
+ cgf.cgm .errorNYI (e->getSourceRange (), " Unary inc/dec other fp type" );
210
+ return {};
211
+ }
212
+ } else if (type->isFixedPointType ()) {
213
+ cgf.cgm .errorNYI (e->getSourceRange (), " Unary inc/dec other fixed point" );
214
+ return {};
215
+ } else {
216
+ assert (type->castAs <ObjCObjectPointerType>());
217
+ cgf.cgm .errorNYI (e->getSourceRange (), " Unary inc/dec ObjectiveC pointer" );
218
+ return {};
219
+ }
220
+
221
+ CIRGenFunction::SourceLocRAIIObject sourceloc{
222
+ cgf, cgf.getLoc (e->getSourceRange ())};
223
+
224
+ // Store the updated result through the lvalue
225
+ if (lv.isBitField ()) {
226
+ cgf.cgm .errorNYI (e->getSourceRange (), " Unary inc/dec bitfield" );
227
+ return {};
228
+ } else {
229
+ cgf.emitStoreThroughLValue (RValue::get (value), lv);
230
+ }
231
+
232
+ // If this is a postinc, return the value read from memory, otherwise use
233
+ // the updated value.
234
+ return isPre ? value : input;
235
+ }
236
+
237
+ mlir::Value emitIncDecConsiderOverflowBehavior (const UnaryOperator *e,
238
+ mlir::Value inVal,
239
+ bool isInc) {
240
+ assert (!cir::MissingFeatures::opUnarySignedOverflow ());
241
+ cir::UnaryOpKind kind =
242
+ e->isIncrementOp () ? cir::UnaryOpKind::Inc : cir::UnaryOpKind::Dec;
243
+ switch (cgf.getLangOpts ().getSignedOverflowBehavior ()) {
244
+ case LangOptions::SOB_Defined:
245
+ return emitUnaryOp (e, kind, inVal);
246
+ case LangOptions::SOB_Undefined:
247
+ assert (!cir::MissingFeatures::sanitizers ());
248
+ return emitUnaryOp (e, kind, inVal);
249
+ break ;
250
+ case LangOptions::SOB_Trapping:
251
+ if (!e->canOverflow ())
252
+ return emitUnaryOp (e, kind, inVal);
253
+ cgf.cgm .errorNYI (e->getSourceRange (), " inc/def overflow SOB_Trapping" );
254
+ return {};
255
+ }
256
+ llvm_unreachable (" Unexpected signed overflow behavior kind" );
257
+ }
258
+
259
+ mlir::Value VisitUnaryPlus (const UnaryOperator *e,
260
+ QualType promotionType = QualType()) {
261
+ if (!promotionType.isNull ())
262
+ cgf.cgm .errorNYI (e->getSourceRange (), " VisitUnaryPlus: promotionType" );
263
+ assert (!cir::MissingFeatures::opUnaryPromotionType ());
264
+ mlir::Value result = VisitPlus (e);
265
+ return result;
266
+ }
267
+
268
+ mlir::Value VisitPlus (const UnaryOperator *e) {
269
+ // This differs from gcc, though, most likely due to a bug in gcc.
270
+ ignoreResultAssign = false ;
271
+
272
+ assert (!cir::MissingFeatures::opUnaryPromotionType ());
273
+ mlir::Value operand = Visit (e->getSubExpr ());
274
+
275
+ return emitUnaryOp (e, cir::UnaryOpKind::Plus, operand);
276
+ }
277
+
278
+ mlir::Value VisitUnaryMinus (const UnaryOperator *e,
279
+ QualType promotionType = QualType()) {
280
+ if (!promotionType.isNull ())
281
+ cgf.cgm .errorNYI (e->getSourceRange (), " VisitUnaryMinus: promotionType" );
282
+ assert (!cir::MissingFeatures::opUnaryPromotionType ());
283
+ mlir::Value result = VisitMinus (e);
284
+ return result;
285
+ }
286
+
287
+ mlir::Value VisitMinus (const UnaryOperator *e) {
288
+ ignoreResultAssign = false ;
289
+
290
+ assert (!cir::MissingFeatures::opUnaryPromotionType ());
291
+ mlir::Value operand = Visit (e->getSubExpr ());
292
+
293
+ assert (!cir::MissingFeatures::opUnarySignedOverflow ());
294
+
295
+ // NOTE: LLVM codegen will lower this directly to either a FNeg
296
+ // or a Sub instruction. In CIR this will be handled later in LowerToLLVM.
297
+ return emitUnaryOp (e, cir::UnaryOpKind::Minus, operand);
298
+ }
299
+
300
+ mlir::Value emitUnaryOp (const UnaryOperator *e, cir::UnaryOpKind kind,
301
+ mlir::Value input) {
302
+ return builder.create <cir::UnaryOp>(
303
+ cgf.getLoc (e->getSourceRange ().getBegin ()), input.getType (), kind,
304
+ input);
305
+ }
306
+
307
+ mlir::Value VisitUnaryNot (const UnaryOperator *e) {
308
+ ignoreResultAssign = false ;
309
+ mlir::Value op = Visit (e->getSubExpr ());
310
+ return emitUnaryOp (e, cir::UnaryOpKind::Not, op);
311
+ }
312
+
97
313
// / Emit a conversion from the specified type to the specified destination
98
314
// / type, both of which are CIR scalar types.
99
315
// / TODO: do we need ScalarConversionOpts here? Should be done in another
@@ -188,3 +404,10 @@ mlir::Value ScalarExprEmitter::VisitUnaryExprOrTypeTraitExpr(
188
404
loc, builder.getAttr <cir::IntAttr>(
189
405
cgf.cgm .UInt64Ty , e->EvaluateKnownConstInt (cgf.getContext ())));
190
406
}
407
+
408
+ mlir::Value CIRGenFunction::emitScalarPrePostIncDec (const UnaryOperator *E,
409
+ LValue LV, bool isInc,
410
+ bool isPre) {
411
+ return ScalarExprEmitter (*this , builder)
412
+ .emitScalarPrePostIncDec (E, LV, isInc, isPre);
413
+ }
0 commit comments