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