Path: blob/main/contrib/llvm-project/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
213799 views
//===----------------------------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// Emit Expr nodes with scalar CIR types as CIR code.9//10//===----------------------------------------------------------------------===//1112#include "CIRGenFunction.h"13#include "CIRGenValue.h"1415#include "clang/AST/Expr.h"16#include "clang/AST/StmtVisitor.h"17#include "clang/CIR/MissingFeatures.h"1819#include "mlir/IR/Location.h"20#include "mlir/IR/Value.h"2122#include <cassert>23#include <utility>2425using namespace clang;26using namespace clang::CIRGen;2728namespace {2930struct BinOpInfo {31mlir::Value lhs;32mlir::Value rhs;33SourceRange loc;34QualType fullType; // Type of operands and result35QualType compType; // Type used for computations. Element type36// for vectors, otherwise same as FullType.37BinaryOperator::Opcode opcode; // Opcode of BinOp to perform38FPOptions fpfeatures;39const Expr *e; // Entire expr, for error unsupported. May not be binop.4041/// Check if the binop computes a division or a remainder.42bool isDivRemOp() const {43return opcode == BO_Div || opcode == BO_Rem || opcode == BO_DivAssign ||44opcode == BO_RemAssign;45}4647/// Check if the binop can result in integer overflow.48bool mayHaveIntegerOverflow() const {49// Without constant input, we can't rule out overflow.50auto lhsci = dyn_cast<cir::ConstantOp>(lhs.getDefiningOp());51auto rhsci = dyn_cast<cir::ConstantOp>(rhs.getDefiningOp());52if (!lhsci || !rhsci)53return true;5455assert(!cir::MissingFeatures::mayHaveIntegerOverflow());56// TODO(cir): For now we just assume that we might overflow57return true;58}5960/// Check if at least one operand is a fixed point type. In such cases,61/// this operation did not follow usual arithmetic conversion and both62/// operands might not be of the same type.63bool isFixedPointOp() const {64// We cannot simply check the result type since comparison operations65// return an int.66if (const auto *binOp = llvm::dyn_cast<BinaryOperator>(e)) {67QualType lhstype = binOp->getLHS()->getType();68QualType rhstype = binOp->getRHS()->getType();69return lhstype->isFixedPointType() || rhstype->isFixedPointType();70}71if (const auto *unop = llvm::dyn_cast<UnaryOperator>(e))72return unop->getSubExpr()->getType()->isFixedPointType();73return false;74}75};7677class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {78CIRGenFunction &cgf;79CIRGenBuilderTy &builder;80bool ignoreResultAssign;8182public:83ScalarExprEmitter(CIRGenFunction &cgf, CIRGenBuilderTy &builder)84: cgf(cgf), builder(builder) {}8586//===--------------------------------------------------------------------===//87// Utilities88//===--------------------------------------------------------------------===//8990mlir::Value emitPromotedValue(mlir::Value result, QualType promotionType) {91return builder.createFloatingCast(result, cgf.convertType(promotionType));92}9394mlir::Value emitUnPromotedValue(mlir::Value result, QualType exprType) {95return builder.createFloatingCast(result, cgf.convertType(exprType));96}9798mlir::Value emitPromoted(const Expr *e, QualType promotionType);99100mlir::Value maybePromoteBoolResult(mlir::Value value,101mlir::Type dstTy) const {102if (mlir::isa<cir::IntType>(dstTy))103return builder.createBoolToInt(value, dstTy);104if (mlir::isa<cir::BoolType>(dstTy))105return value;106llvm_unreachable("Can only promote integer or boolean types");107}108109//===--------------------------------------------------------------------===//110// Visitor Methods111//===--------------------------------------------------------------------===//112113mlir::Value Visit(Expr *e) {114return StmtVisitor<ScalarExprEmitter, mlir::Value>::Visit(e);115}116117mlir::Value VisitStmt(Stmt *s) {118llvm_unreachable("Statement passed to ScalarExprEmitter");119}120121mlir::Value VisitExpr(Expr *e) {122cgf.getCIRGenModule().errorNYI(123e->getSourceRange(), "scalar expression kind: ", e->getStmtClassName());124return {};125}126127mlir::Value VisitPackIndexingExpr(PackIndexingExpr *e) {128return Visit(e->getSelectedExpr());129}130131mlir::Value VisitParenExpr(ParenExpr *pe) { return Visit(pe->getSubExpr()); }132133mlir::Value VisitGenericSelectionExpr(GenericSelectionExpr *ge) {134return Visit(ge->getResultExpr());135}136137/// Emits the address of the l-value, then loads and returns the result.138mlir::Value emitLoadOfLValue(const Expr *e) {139LValue lv = cgf.emitLValue(e);140// FIXME: add some akin to EmitLValueAlignmentAssumption(E, V);141return cgf.emitLoadOfLValue(lv, e->getExprLoc()).getValue();142}143144mlir::Value emitLoadOfLValue(LValue lv, SourceLocation loc) {145return cgf.emitLoadOfLValue(lv, loc).getValue();146}147148// l-values149mlir::Value VisitDeclRefExpr(DeclRefExpr *e) {150if (CIRGenFunction::ConstantEmission constant = cgf.tryEmitAsConstant(e))151return cgf.emitScalarConstant(constant, e);152153return emitLoadOfLValue(e);154}155156mlir::Value VisitIntegerLiteral(const IntegerLiteral *e) {157mlir::Type type = cgf.convertType(e->getType());158return builder.create<cir::ConstantOp>(159cgf.getLoc(e->getExprLoc()), cir::IntAttr::get(type, e->getValue()));160}161162mlir::Value VisitFloatingLiteral(const FloatingLiteral *e) {163mlir::Type type = cgf.convertType(e->getType());164assert(mlir::isa<cir::FPTypeInterface>(type) &&165"expect floating-point type");166return builder.create<cir::ConstantOp>(167cgf.getLoc(e->getExprLoc()), cir::FPAttr::get(type, e->getValue()));168}169170mlir::Value VisitCharacterLiteral(const CharacterLiteral *e) {171mlir::Type ty = cgf.convertType(e->getType());172auto init = cir::IntAttr::get(ty, e->getValue());173return builder.create<cir::ConstantOp>(cgf.getLoc(e->getExprLoc()), init);174}175176mlir::Value VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *e) {177return builder.getBool(e->getValue(), cgf.getLoc(e->getExprLoc()));178}179180mlir::Value VisitCastExpr(CastExpr *e);181mlir::Value VisitCallExpr(const CallExpr *e);182183mlir::Value VisitArraySubscriptExpr(ArraySubscriptExpr *e) {184if (e->getBase()->getType()->isVectorType()) {185assert(!cir::MissingFeatures::scalableVectors());186187const mlir::Location loc = cgf.getLoc(e->getSourceRange());188const mlir::Value vecValue = Visit(e->getBase());189const mlir::Value indexValue = Visit(e->getIdx());190return cgf.builder.create<cir::VecExtractOp>(loc, vecValue, indexValue);191}192// Just load the lvalue formed by the subscript expression.193return emitLoadOfLValue(e);194}195196mlir::Value VisitShuffleVectorExpr(ShuffleVectorExpr *e) {197if (e->getNumSubExprs() == 2) {198// The undocumented form of __builtin_shufflevector.199mlir::Value inputVec = Visit(e->getExpr(0));200mlir::Value indexVec = Visit(e->getExpr(1));201return cgf.builder.create<cir::VecShuffleDynamicOp>(202cgf.getLoc(e->getSourceRange()), inputVec, indexVec);203}204205mlir::Value vec1 = Visit(e->getExpr(0));206mlir::Value vec2 = Visit(e->getExpr(1));207208// The documented form of __builtin_shufflevector, where the indices are209// a variable number of integer constants. The constants will be stored210// in an ArrayAttr.211SmallVector<mlir::Attribute, 8> indices;212for (unsigned i = 2; i < e->getNumSubExprs(); ++i) {213indices.push_back(214cir::IntAttr::get(cgf.builder.getSInt64Ty(),215e->getExpr(i)216->EvaluateKnownConstInt(cgf.getContext())217.getSExtValue()));218}219220return cgf.builder.create<cir::VecShuffleOp>(221cgf.getLoc(e->getSourceRange()), cgf.convertType(e->getType()), vec1,222vec2, cgf.builder.getArrayAttr(indices));223}224225mlir::Value VisitConvertVectorExpr(ConvertVectorExpr *e) {226// __builtin_convertvector is an element-wise cast, and is implemented as a227// regular cast. The back end handles casts of vectors correctly.228return emitScalarConversion(Visit(e->getSrcExpr()),229e->getSrcExpr()->getType(), e->getType(),230e->getSourceRange().getBegin());231}232233mlir::Value VisitMemberExpr(MemberExpr *e);234235mlir::Value VisitInitListExpr(InitListExpr *e);236237mlir::Value VisitExplicitCastExpr(ExplicitCastExpr *e) {238return VisitCastExpr(e);239}240241mlir::Value VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *e) {242return cgf.cgm.emitNullConstant(e->getType(),243cgf.getLoc(e->getSourceRange()));244}245246/// Perform a pointer to boolean conversion.247mlir::Value emitPointerToBoolConversion(mlir::Value v, QualType qt) {248// TODO(cir): comparing the ptr to null is done when lowering CIR to LLVM.249// We might want to have a separate pass for these types of conversions.250return cgf.getBuilder().createPtrToBoolCast(v);251}252253mlir::Value emitFloatToBoolConversion(mlir::Value src, mlir::Location loc) {254cir::BoolType boolTy = builder.getBoolTy();255return builder.create<cir::CastOp>(loc, boolTy,256cir::CastKind::float_to_bool, src);257}258259mlir::Value emitIntToBoolConversion(mlir::Value srcVal, mlir::Location loc) {260// Because of the type rules of C, we often end up computing a261// logical value, then zero extending it to int, then wanting it262// as a logical value again.263// TODO: optimize this common case here or leave it for later264// CIR passes?265cir::BoolType boolTy = builder.getBoolTy();266return builder.create<cir::CastOp>(loc, boolTy, cir::CastKind::int_to_bool,267srcVal);268}269270/// Convert the specified expression value to a boolean (!cir.bool) truth271/// value. This is equivalent to "Val != 0".272mlir::Value emitConversionToBool(mlir::Value src, QualType srcType,273mlir::Location loc) {274assert(srcType.isCanonical() && "EmitScalarConversion strips typedefs");275276if (srcType->isRealFloatingType())277return emitFloatToBoolConversion(src, loc);278279if (llvm::isa<MemberPointerType>(srcType)) {280cgf.getCIRGenModule().errorNYI(loc, "member pointer to bool conversion");281return builder.getFalse(loc);282}283284if (srcType->isIntegerType())285return emitIntToBoolConversion(src, loc);286287assert(::mlir::isa<cir::PointerType>(src.getType()));288return emitPointerToBoolConversion(src, srcType);289}290291// Emit a conversion from the specified type to the specified destination292// type, both of which are CIR scalar types.293struct ScalarConversionOpts {294bool treatBooleanAsSigned;295bool emitImplicitIntegerTruncationChecks;296bool emitImplicitIntegerSignChangeChecks;297298ScalarConversionOpts()299: treatBooleanAsSigned(false),300emitImplicitIntegerTruncationChecks(false),301emitImplicitIntegerSignChangeChecks(false) {}302303ScalarConversionOpts(clang::SanitizerSet sanOpts)304: treatBooleanAsSigned(false),305emitImplicitIntegerTruncationChecks(306sanOpts.hasOneOf(SanitizerKind::ImplicitIntegerTruncation)),307emitImplicitIntegerSignChangeChecks(308sanOpts.has(SanitizerKind::ImplicitIntegerSignChange)) {}309};310311// Conversion from bool, integral, or floating-point to integral or312// floating-point. Conversions involving other types are handled elsewhere.313// Conversion to bool is handled elsewhere because that's a comparison against314// zero, not a simple cast. This handles both individual scalars and vectors.315mlir::Value emitScalarCast(mlir::Value src, QualType srcType,316QualType dstType, mlir::Type srcTy,317mlir::Type dstTy, ScalarConversionOpts opts) {318assert(!srcType->isMatrixType() && !dstType->isMatrixType() &&319"Internal error: matrix types not handled by this function.");320assert(!(mlir::isa<mlir::IntegerType>(srcTy) ||321mlir::isa<mlir::IntegerType>(dstTy)) &&322"Obsolete code. Don't use mlir::IntegerType with CIR.");323324mlir::Type fullDstTy = dstTy;325if (mlir::isa<cir::VectorType>(srcTy) &&326mlir::isa<cir::VectorType>(dstTy)) {327// Use the element types of the vectors to figure out the CastKind.328srcTy = mlir::dyn_cast<cir::VectorType>(srcTy).getElementType();329dstTy = mlir::dyn_cast<cir::VectorType>(dstTy).getElementType();330}331332std::optional<cir::CastKind> castKind;333334if (mlir::isa<cir::BoolType>(srcTy)) {335if (opts.treatBooleanAsSigned)336cgf.getCIRGenModule().errorNYI("signed bool");337if (cgf.getBuilder().isInt(dstTy))338castKind = cir::CastKind::bool_to_int;339else if (mlir::isa<cir::FPTypeInterface>(dstTy))340castKind = cir::CastKind::bool_to_float;341else342llvm_unreachable("Internal error: Cast to unexpected type");343} else if (cgf.getBuilder().isInt(srcTy)) {344if (cgf.getBuilder().isInt(dstTy))345castKind = cir::CastKind::integral;346else if (mlir::isa<cir::FPTypeInterface>(dstTy))347castKind = cir::CastKind::int_to_float;348else349llvm_unreachable("Internal error: Cast to unexpected type");350} else if (mlir::isa<cir::FPTypeInterface>(srcTy)) {351if (cgf.getBuilder().isInt(dstTy)) {352// If we can't recognize overflow as undefined behavior, assume that353// overflow saturates. This protects against normal optimizations if we354// are compiling with non-standard FP semantics.355if (!cgf.cgm.getCodeGenOpts().StrictFloatCastOverflow)356cgf.getCIRGenModule().errorNYI("strict float cast overflow");357assert(!cir::MissingFeatures::fpConstraints());358castKind = cir::CastKind::float_to_int;359} else if (mlir::isa<cir::FPTypeInterface>(dstTy)) {360// TODO: split this to createFPExt/createFPTrunc361return builder.createFloatingCast(src, fullDstTy);362} else {363llvm_unreachable("Internal error: Cast to unexpected type");364}365} else {366llvm_unreachable("Internal error: Cast from unexpected type");367}368369assert(castKind.has_value() && "Internal error: CastKind not set.");370return builder.create<cir::CastOp>(src.getLoc(), fullDstTy, *castKind, src);371}372373mlir::Value374VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *e) {375return Visit(e->getReplacement());376}377378mlir::Value VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *e);379mlir::Value380VisitAbstractConditionalOperator(const AbstractConditionalOperator *e);381382// Unary Operators.383mlir::Value VisitUnaryPostDec(const UnaryOperator *e) {384LValue lv = cgf.emitLValue(e->getSubExpr());385return emitScalarPrePostIncDec(e, lv, false, false);386}387mlir::Value VisitUnaryPostInc(const UnaryOperator *e) {388LValue lv = cgf.emitLValue(e->getSubExpr());389return emitScalarPrePostIncDec(e, lv, true, false);390}391mlir::Value VisitUnaryPreDec(const UnaryOperator *e) {392LValue lv = cgf.emitLValue(e->getSubExpr());393return emitScalarPrePostIncDec(e, lv, false, true);394}395mlir::Value VisitUnaryPreInc(const UnaryOperator *e) {396LValue lv = cgf.emitLValue(e->getSubExpr());397return emitScalarPrePostIncDec(e, lv, true, true);398}399mlir::Value emitScalarPrePostIncDec(const UnaryOperator *e, LValue lv,400bool isInc, bool isPre) {401if (cgf.getLangOpts().OpenMP)402cgf.cgm.errorNYI(e->getSourceRange(), "inc/dec OpenMP");403404QualType type = e->getSubExpr()->getType();405406mlir::Value value;407mlir::Value input;408409if (type->getAs<AtomicType>()) {410cgf.cgm.errorNYI(e->getSourceRange(), "Atomic inc/dec");411// TODO(cir): This is not correct, but it will produce reasonable code412// until atomic operations are implemented.413value = cgf.emitLoadOfLValue(lv, e->getExprLoc()).getValue();414input = value;415} else {416value = cgf.emitLoadOfLValue(lv, e->getExprLoc()).getValue();417input = value;418}419420// NOTE: When possible, more frequent cases are handled first.421422// Special case of integer increment that we have to check first: bool++.423// Due to promotion rules, we get:424// bool++ -> bool = bool + 1425// -> bool = (int)bool + 1426// -> bool = ((int)bool + 1 != 0)427// An interesting aspect of this is that increment is always true.428// Decrement does not have this property.429if (isInc && type->isBooleanType()) {430value = builder.getTrue(cgf.getLoc(e->getExprLoc()));431} else if (type->isIntegerType()) {432QualType promotedType;433bool canPerformLossyDemotionCheck = false;434if (cgf.getContext().isPromotableIntegerType(type)) {435promotedType = cgf.getContext().getPromotedIntegerType(type);436assert(promotedType != type && "Shouldn't promote to the same type.");437canPerformLossyDemotionCheck = true;438canPerformLossyDemotionCheck &=439cgf.getContext().getCanonicalType(type) !=440cgf.getContext().getCanonicalType(promotedType);441canPerformLossyDemotionCheck &=442type->isIntegerType() && promotedType->isIntegerType();443444// TODO(cir): Currently, we store bitwidths in CIR types only for445// integers. This might also be required for other types.446447assert(448(!canPerformLossyDemotionCheck ||449type->isSignedIntegerOrEnumerationType() ||450promotedType->isSignedIntegerOrEnumerationType() ||451mlir::cast<cir::IntType>(cgf.convertType(type)).getWidth() ==452mlir::cast<cir::IntType>(cgf.convertType(type)).getWidth()) &&453"The following check expects that if we do promotion to different "454"underlying canonical type, at least one of the types (either "455"base or promoted) will be signed, or the bitwidths will match.");456}457458assert(!cir::MissingFeatures::sanitizers());459if (e->canOverflow() && type->isSignedIntegerOrEnumerationType()) {460value = emitIncDecConsiderOverflowBehavior(e, value, isInc);461} else {462cir::UnaryOpKind kind =463e->isIncrementOp() ? cir::UnaryOpKind::Inc : cir::UnaryOpKind::Dec;464// NOTE(CIR): clang calls CreateAdd but folds this to a unary op465value = emitUnaryOp(e, kind, input, /*nsw=*/false);466}467} else if (const PointerType *ptr = type->getAs<PointerType>()) {468QualType type = ptr->getPointeeType();469if (cgf.getContext().getAsVariableArrayType(type)) {470// VLA types don't have constant size.471cgf.cgm.errorNYI(e->getSourceRange(), "Pointer arithmetic on VLA");472return {};473} else if (type->isFunctionType()) {474// Arithmetic on function pointers (!) is just +-1.475cgf.cgm.errorNYI(e->getSourceRange(),476"Pointer arithmetic on function pointer");477return {};478} else {479// For everything else, we can just do a simple increment.480mlir::Location loc = cgf.getLoc(e->getSourceRange());481CIRGenBuilderTy &builder = cgf.getBuilder();482int amount = (isInc ? 1 : -1);483mlir::Value amt = builder.getSInt32(amount, loc);484assert(!cir::MissingFeatures::sanitizers());485value = builder.createPtrStride(loc, value, amt);486}487} else if (type->isVectorType()) {488cgf.cgm.errorNYI(e->getSourceRange(), "Unary inc/dec vector");489return {};490} else if (type->isRealFloatingType()) {491assert(!cir::MissingFeatures::cgFPOptionsRAII());492493if (type->isHalfType() &&494!cgf.getContext().getLangOpts().NativeHalfType) {495cgf.cgm.errorNYI(e->getSourceRange(), "Unary inc/dec half");496return {};497}498499if (mlir::isa<cir::SingleType, cir::DoubleType>(value.getType())) {500// Create the inc/dec operation.501// NOTE(CIR): clang calls CreateAdd but folds this to a unary op502cir::UnaryOpKind kind =503(isInc ? cir::UnaryOpKind::Inc : cir::UnaryOpKind::Dec);504value = emitUnaryOp(e, kind, value);505} else {506cgf.cgm.errorNYI(e->getSourceRange(), "Unary inc/dec other fp type");507return {};508}509} else if (type->isFixedPointType()) {510cgf.cgm.errorNYI(e->getSourceRange(), "Unary inc/dec other fixed point");511return {};512} else {513assert(type->castAs<ObjCObjectPointerType>());514cgf.cgm.errorNYI(e->getSourceRange(), "Unary inc/dec ObjectiveC pointer");515return {};516}517518CIRGenFunction::SourceLocRAIIObject sourceloc{519cgf, cgf.getLoc(e->getSourceRange())};520521// Store the updated result through the lvalue522if (lv.isBitField())523return cgf.emitStoreThroughBitfieldLValue(RValue::get(value), lv);524else525cgf.emitStoreThroughLValue(RValue::get(value), lv);526527// If this is a postinc, return the value read from memory, otherwise use528// the updated value.529return isPre ? value : input;530}531532mlir::Value emitIncDecConsiderOverflowBehavior(const UnaryOperator *e,533mlir::Value inVal,534bool isInc) {535cir::UnaryOpKind kind =536e->isIncrementOp() ? cir::UnaryOpKind::Inc : cir::UnaryOpKind::Dec;537switch (cgf.getLangOpts().getSignedOverflowBehavior()) {538case LangOptions::SOB_Defined:539return emitUnaryOp(e, kind, inVal, /*nsw=*/false);540case LangOptions::SOB_Undefined:541assert(!cir::MissingFeatures::sanitizers());542return emitUnaryOp(e, kind, inVal, /*nsw=*/true);543case LangOptions::SOB_Trapping:544if (!e->canOverflow())545return emitUnaryOp(e, kind, inVal, /*nsw=*/true);546cgf.cgm.errorNYI(e->getSourceRange(), "inc/def overflow SOB_Trapping");547return {};548}549llvm_unreachable("Unexpected signed overflow behavior kind");550}551552mlir::Value VisitUnaryAddrOf(const UnaryOperator *e) {553if (llvm::isa<MemberPointerType>(e->getType())) {554cgf.cgm.errorNYI(e->getSourceRange(), "Address of member pointer");555return builder.getNullPtr(cgf.convertType(e->getType()),556cgf.getLoc(e->getExprLoc()));557}558559return cgf.emitLValue(e->getSubExpr()).getPointer();560}561562mlir::Value VisitUnaryDeref(const UnaryOperator *e) {563if (e->getType()->isVoidType())564return Visit(e->getSubExpr()); // the actual value should be unused565return emitLoadOfLValue(e);566}567568mlir::Value VisitUnaryPlus(const UnaryOperator *e) {569return emitUnaryPlusOrMinus(e, cir::UnaryOpKind::Plus);570}571572mlir::Value VisitUnaryMinus(const UnaryOperator *e) {573return emitUnaryPlusOrMinus(e, cir::UnaryOpKind::Minus);574}575576mlir::Value emitUnaryPlusOrMinus(const UnaryOperator *e,577cir::UnaryOpKind kind) {578ignoreResultAssign = false;579580QualType promotionType = getPromotionType(e->getSubExpr()->getType());581582mlir::Value operand;583if (!promotionType.isNull())584operand = cgf.emitPromotedScalarExpr(e->getSubExpr(), promotionType);585else586operand = Visit(e->getSubExpr());587588bool nsw =589kind == cir::UnaryOpKind::Minus && e->getType()->isSignedIntegerType();590591// NOTE: LLVM codegen will lower this directly to either a FNeg592// or a Sub instruction. In CIR this will be handled later in LowerToLLVM.593mlir::Value result = emitUnaryOp(e, kind, operand, nsw);594if (result && !promotionType.isNull())595return emitUnPromotedValue(result, e->getType());596return result;597}598599mlir::Value emitUnaryOp(const UnaryOperator *e, cir::UnaryOpKind kind,600mlir::Value input, bool nsw = false) {601return builder.create<cir::UnaryOp>(602cgf.getLoc(e->getSourceRange().getBegin()), input.getType(), kind,603input, nsw);604}605606mlir::Value VisitUnaryNot(const UnaryOperator *e) {607ignoreResultAssign = false;608mlir::Value op = Visit(e->getSubExpr());609return emitUnaryOp(e, cir::UnaryOpKind::Not, op);610}611612mlir::Value VisitUnaryLNot(const UnaryOperator *e);613614mlir::Value VisitUnaryReal(const UnaryOperator *e);615616mlir::Value VisitUnaryImag(const UnaryOperator *e);617618mlir::Value VisitCXXThisExpr(CXXThisExpr *te) { return cgf.loadCXXThis(); }619620mlir::Value VisitCXXNewExpr(const CXXNewExpr *e) {621return cgf.emitCXXNewExpr(e);622}623624/// Emit a conversion from the specified type to the specified destination625/// type, both of which are CIR scalar types.626/// TODO: do we need ScalarConversionOpts here? Should be done in another627/// pass.628mlir::Value629emitScalarConversion(mlir::Value src, QualType srcType, QualType dstType,630SourceLocation loc,631ScalarConversionOpts opts = ScalarConversionOpts()) {632// All conversions involving fixed point types should be handled by the633// emitFixedPoint family functions. This is done to prevent bloating up634// this function more, and although fixed point numbers are represented by635// integers, we do not want to follow any logic that assumes they should be636// treated as integers.637// TODO(leonardchan): When necessary, add another if statement checking for638// conversions to fixed point types from other types.639// conversions to fixed point types from other types.640if (srcType->isFixedPointType() || dstType->isFixedPointType()) {641cgf.getCIRGenModule().errorNYI(loc, "fixed point conversions");642return {};643}644645srcType = srcType.getCanonicalType();646dstType = dstType.getCanonicalType();647if (srcType == dstType) {648if (opts.emitImplicitIntegerSignChangeChecks)649cgf.getCIRGenModule().errorNYI(loc,650"implicit integer sign change checks");651return src;652}653654if (dstType->isVoidType())655return {};656657mlir::Type mlirSrcType = src.getType();658659// Handle conversions to bool first, they are special: comparisons against660// 0.661if (dstType->isBooleanType())662return emitConversionToBool(src, srcType, cgf.getLoc(loc));663664mlir::Type mlirDstType = cgf.convertType(dstType);665666if (srcType->isHalfType() &&667!cgf.getContext().getLangOpts().NativeHalfType) {668// Cast to FP using the intrinsic if the half type itself isn't supported.669if (mlir::isa<cir::FPTypeInterface>(mlirDstType)) {670if (cgf.getContext().getTargetInfo().useFP16ConversionIntrinsics())671cgf.getCIRGenModule().errorNYI(loc,672"cast via llvm.convert.from.fp16");673} else {674// Cast to other types through float, using either the intrinsic or675// FPExt, depending on whether the half type itself is supported (as676// opposed to operations on half, available with NativeHalfType).677if (cgf.getContext().getTargetInfo().useFP16ConversionIntrinsics())678cgf.getCIRGenModule().errorNYI(loc,679"cast via llvm.convert.from.fp16");680// FIXME(cir): For now lets pretend we shouldn't use the conversion681// intrinsics and insert a cast here unconditionally.682src = builder.createCast(cgf.getLoc(loc), cir::CastKind::floating, src,683cgf.FloatTy);684srcType = cgf.getContext().FloatTy;685mlirSrcType = cgf.FloatTy;686}687}688689// TODO(cir): LLVM codegen ignore conversions like int -> uint,690// is there anything to be done for CIR here?691if (mlirSrcType == mlirDstType) {692if (opts.emitImplicitIntegerSignChangeChecks)693cgf.getCIRGenModule().errorNYI(loc,694"implicit integer sign change checks");695return src;696}697698// Handle pointer conversions next: pointers can only be converted to/from699// other pointers and integers. Check for pointer types in terms of LLVM, as700// some native types (like Obj-C id) may map to a pointer type.701if (auto dstPT = dyn_cast<cir::PointerType>(mlirDstType)) {702cgf.getCIRGenModule().errorNYI(loc, "pointer casts");703return builder.getNullPtr(dstPT, src.getLoc());704}705706if (isa<cir::PointerType>(mlirSrcType)) {707// Must be an ptr to int cast.708assert(isa<cir::IntType>(mlirDstType) && "not ptr->int?");709return builder.createPtrToInt(src, mlirDstType);710}711712// A scalar can be splatted to an extended vector of the same element type713if (dstType->isExtVectorType() && !srcType->isVectorType()) {714// Sema should add casts to make sure that the source expression's type715// is the same as the vector's element type (sans qualifiers)716assert(dstType->castAs<ExtVectorType>()->getElementType().getTypePtr() ==717srcType.getTypePtr() &&718"Splatted expr doesn't match with vector element type?");719720cgf.getCIRGenModule().errorNYI(loc, "vector splatting");721return {};722}723724if (srcType->isMatrixType() && dstType->isMatrixType()) {725cgf.getCIRGenModule().errorNYI(loc,726"matrix type to matrix type conversion");727return {};728}729assert(!srcType->isMatrixType() && !dstType->isMatrixType() &&730"Internal error: conversion between matrix type and scalar type");731732// Finally, we have the arithmetic types or vectors of arithmetic types.733mlir::Value res = nullptr;734mlir::Type resTy = mlirDstType;735736res = emitScalarCast(src, srcType, dstType, mlirSrcType, mlirDstType, opts);737738if (mlirDstType != resTy) {739if (cgf.getContext().getTargetInfo().useFP16ConversionIntrinsics()) {740cgf.getCIRGenModule().errorNYI(loc, "cast via llvm.convert.to.fp16");741}742// FIXME(cir): For now we never use FP16 conversion intrinsics even if743// required by the target. Change that once this is implemented744res = builder.createCast(cgf.getLoc(loc), cir::CastKind::floating, res,745resTy);746}747748if (opts.emitImplicitIntegerTruncationChecks)749cgf.getCIRGenModule().errorNYI(loc, "implicit integer truncation checks");750751if (opts.emitImplicitIntegerSignChangeChecks)752cgf.getCIRGenModule().errorNYI(loc,753"implicit integer sign change checks");754755return res;756}757758BinOpInfo emitBinOps(const BinaryOperator *e,759QualType promotionType = QualType()) {760BinOpInfo result;761result.lhs = cgf.emitPromotedScalarExpr(e->getLHS(), promotionType);762result.rhs = cgf.emitPromotedScalarExpr(e->getRHS(), promotionType);763if (!promotionType.isNull())764result.fullType = promotionType;765else766result.fullType = e->getType();767result.compType = result.fullType;768if (const auto *vecType = dyn_cast_or_null<VectorType>(result.fullType)) {769result.compType = vecType->getElementType();770}771result.opcode = e->getOpcode();772result.loc = e->getSourceRange();773// TODO(cir): Result.FPFeatures774assert(!cir::MissingFeatures::cgFPOptionsRAII());775result.e = e;776return result;777}778779mlir::Value emitMul(const BinOpInfo &ops);780mlir::Value emitDiv(const BinOpInfo &ops);781mlir::Value emitRem(const BinOpInfo &ops);782mlir::Value emitAdd(const BinOpInfo &ops);783mlir::Value emitSub(const BinOpInfo &ops);784mlir::Value emitShl(const BinOpInfo &ops);785mlir::Value emitShr(const BinOpInfo &ops);786mlir::Value emitAnd(const BinOpInfo &ops);787mlir::Value emitXor(const BinOpInfo &ops);788mlir::Value emitOr(const BinOpInfo &ops);789790LValue emitCompoundAssignLValue(791const CompoundAssignOperator *e,792mlir::Value (ScalarExprEmitter::*f)(const BinOpInfo &),793mlir::Value &result);794mlir::Value795emitCompoundAssign(const CompoundAssignOperator *e,796mlir::Value (ScalarExprEmitter::*f)(const BinOpInfo &));797798// TODO(cir): Candidate to be in a common AST helper between CIR and LLVM799// codegen.800QualType getPromotionType(QualType ty) {801if (ty->getAs<ComplexType>()) {802assert(!cir::MissingFeatures::complexType());803cgf.cgm.errorNYI("promotion to complex type");804return QualType();805}806if (ty.UseExcessPrecision(cgf.getContext())) {807if (ty->getAs<VectorType>()) {808assert(!cir::MissingFeatures::vectorType());809cgf.cgm.errorNYI("promotion to vector type");810return QualType();811}812return cgf.getContext().FloatTy;813}814return QualType();815}816817// Binary operators and binary compound assignment operators.818#define HANDLEBINOP(OP) \819mlir::Value VisitBin##OP(const BinaryOperator *e) { \820QualType promotionTy = getPromotionType(e->getType()); \821auto result = emit##OP(emitBinOps(e, promotionTy)); \822if (result && !promotionTy.isNull()) \823result = emitUnPromotedValue(result, e->getType()); \824return result; \825} \826mlir::Value VisitBin##OP##Assign(const CompoundAssignOperator *e) { \827return emitCompoundAssign(e, &ScalarExprEmitter::emit##OP); \828}829830HANDLEBINOP(Mul)831HANDLEBINOP(Div)832HANDLEBINOP(Rem)833HANDLEBINOP(Add)834HANDLEBINOP(Sub)835HANDLEBINOP(Shl)836HANDLEBINOP(Shr)837HANDLEBINOP(And)838HANDLEBINOP(Xor)839HANDLEBINOP(Or)840#undef HANDLEBINOP841842mlir::Value emitCmp(const BinaryOperator *e) {843const mlir::Location loc = cgf.getLoc(e->getExprLoc());844mlir::Value result;845QualType lhsTy = e->getLHS()->getType();846QualType rhsTy = e->getRHS()->getType();847848auto clangCmpToCIRCmp =849[](clang::BinaryOperatorKind clangCmp) -> cir::CmpOpKind {850switch (clangCmp) {851case BO_LT:852return cir::CmpOpKind::lt;853case BO_GT:854return cir::CmpOpKind::gt;855case BO_LE:856return cir::CmpOpKind::le;857case BO_GE:858return cir::CmpOpKind::ge;859case BO_EQ:860return cir::CmpOpKind::eq;861case BO_NE:862return cir::CmpOpKind::ne;863default:864llvm_unreachable("unsupported comparison kind for cir.cmp");865}866};867868cir::CmpOpKind kind = clangCmpToCIRCmp(e->getOpcode());869if (lhsTy->getAs<MemberPointerType>()) {870assert(!cir::MissingFeatures::dataMemberType());871assert(e->getOpcode() == BO_EQ || e->getOpcode() == BO_NE);872mlir::Value lhs = cgf.emitScalarExpr(e->getLHS());873mlir::Value rhs = cgf.emitScalarExpr(e->getRHS());874result = builder.createCompare(loc, kind, lhs, rhs);875} else if (!lhsTy->isAnyComplexType() && !rhsTy->isAnyComplexType()) {876BinOpInfo boInfo = emitBinOps(e);877mlir::Value lhs = boInfo.lhs;878mlir::Value rhs = boInfo.rhs;879880if (lhsTy->isVectorType()) {881if (!e->getType()->isVectorType()) {882// If AltiVec, the comparison results in a numeric type, so we use883// intrinsics comparing vectors and giving 0 or 1 as a result884cgf.cgm.errorNYI(loc, "AltiVec comparison");885} else {886// Other kinds of vectors. Element-wise comparison returning887// a vector.888result = builder.create<cir::VecCmpOp>(889cgf.getLoc(boInfo.loc), cgf.convertType(boInfo.fullType), kind,890boInfo.lhs, boInfo.rhs);891}892} else if (boInfo.isFixedPointOp()) {893assert(!cir::MissingFeatures::fixedPointType());894cgf.cgm.errorNYI(loc, "fixed point comparisons");895result = builder.getBool(false, loc);896} else {897// integers and pointers898if (cgf.cgm.getCodeGenOpts().StrictVTablePointers &&899mlir::isa<cir::PointerType>(lhs.getType()) &&900mlir::isa<cir::PointerType>(rhs.getType())) {901cgf.cgm.errorNYI(loc, "strict vtable pointer comparisons");902}903904cir::CmpOpKind kind = clangCmpToCIRCmp(e->getOpcode());905result = builder.createCompare(loc, kind, lhs, rhs);906}907} else {908// Complex Comparison: can only be an equality comparison.909assert(e->getOpcode() == BO_EQ || e->getOpcode() == BO_NE);910911BinOpInfo boInfo = emitBinOps(e);912result = builder.create<cir::CmpOp>(loc, kind, boInfo.lhs, boInfo.rhs);913}914915return emitScalarConversion(result, cgf.getContext().BoolTy, e->getType(),916e->getExprLoc());917}918919// Comparisons.920#define VISITCOMP(CODE) \921mlir::Value VisitBin##CODE(const BinaryOperator *E) { return emitCmp(E); }922VISITCOMP(LT)923VISITCOMP(GT)924VISITCOMP(LE)925VISITCOMP(GE)926VISITCOMP(EQ)927VISITCOMP(NE)928#undef VISITCOMP929930mlir::Value VisitBinAssign(const BinaryOperator *e) {931const bool ignore = std::exchange(ignoreResultAssign, false);932933mlir::Value rhs;934LValue lhs;935936switch (e->getLHS()->getType().getObjCLifetime()) {937case Qualifiers::OCL_Strong:938case Qualifiers::OCL_Autoreleasing:939case Qualifiers::OCL_ExplicitNone:940case Qualifiers::OCL_Weak:941assert(!cir::MissingFeatures::objCLifetime());942break;943case Qualifiers::OCL_None:944// __block variables need to have the rhs evaluated first, plus this945// should improve codegen just a little.946rhs = Visit(e->getRHS());947assert(!cir::MissingFeatures::sanitizers());948// TODO(cir): This needs to be emitCheckedLValue() once we support949// sanitizers950lhs = cgf.emitLValue(e->getLHS());951952// Store the value into the LHS. Bit-fields are handled specially because953// the result is altered by the store, i.e., [C99 6.5.16p1]954// 'An assignment expression has the value of the left operand after the955// assignment...'.956if (lhs.isBitField()) {957rhs = cgf.emitStoreThroughBitfieldLValue(RValue::get(rhs), lhs);958} else {959cgf.emitNullabilityCheck(lhs, rhs, e->getExprLoc());960CIRGenFunction::SourceLocRAIIObject loc{961cgf, cgf.getLoc(e->getSourceRange())};962cgf.emitStoreThroughLValue(RValue::get(rhs), lhs);963}964}965966// If the result is clearly ignored, return now.967if (ignore)968return nullptr;969970// The result of an assignment in C is the assigned r-value.971if (!cgf.getLangOpts().CPlusPlus)972return rhs;973974// If the lvalue is non-volatile, return the computed value of the975// assignment.976if (!lhs.isVolatile())977return rhs;978979// Otherwise, reload the value.980return emitLoadOfLValue(lhs, e->getExprLoc());981}982983mlir::Value VisitBinComma(const BinaryOperator *e) {984cgf.emitIgnoredExpr(e->getLHS());985// NOTE: We don't need to EnsureInsertPoint() like LLVM codegen.986return Visit(e->getRHS());987}988989mlir::Value VisitBinLAnd(const clang::BinaryOperator *e) {990if (e->getType()->isVectorType()) {991assert(!cir::MissingFeatures::vectorType());992return {};993}994995assert(!cir::MissingFeatures::instrumentation());996mlir::Type resTy = cgf.convertType(e->getType());997mlir::Location loc = cgf.getLoc(e->getExprLoc());998999CIRGenFunction::ConditionalEvaluation eval(cgf);10001001mlir::Value lhsCondV = cgf.evaluateExprAsBool(e->getLHS());1002auto resOp = builder.create<cir::TernaryOp>(1003loc, lhsCondV, /*trueBuilder=*/1004[&](mlir::OpBuilder &b, mlir::Location loc) {1005CIRGenFunction::LexicalScope lexScope{cgf, loc,1006b.getInsertionBlock()};1007cgf.curLexScope->setAsTernary();1008b.create<cir::YieldOp>(loc, cgf.evaluateExprAsBool(e->getRHS()));1009},1010/*falseBuilder*/1011[&](mlir::OpBuilder &b, mlir::Location loc) {1012CIRGenFunction::LexicalScope lexScope{cgf, loc,1013b.getInsertionBlock()};1014cgf.curLexScope->setAsTernary();1015auto res = b.create<cir::ConstantOp>(loc, builder.getFalseAttr());1016b.create<cir::YieldOp>(loc, res.getRes());1017});1018return maybePromoteBoolResult(resOp.getResult(), resTy);1019}10201021mlir::Value VisitBinLOr(const clang::BinaryOperator *e) {1022if (e->getType()->isVectorType()) {1023assert(!cir::MissingFeatures::vectorType());1024return {};1025}10261027assert(!cir::MissingFeatures::instrumentation());1028mlir::Type resTy = cgf.convertType(e->getType());1029mlir::Location loc = cgf.getLoc(e->getExprLoc());10301031CIRGenFunction::ConditionalEvaluation eval(cgf);10321033mlir::Value lhsCondV = cgf.evaluateExprAsBool(e->getLHS());1034auto resOp = builder.create<cir::TernaryOp>(1035loc, lhsCondV, /*trueBuilder=*/1036[&](mlir::OpBuilder &b, mlir::Location loc) {1037CIRGenFunction::LexicalScope lexScope{cgf, loc,1038b.getInsertionBlock()};1039cgf.curLexScope->setAsTernary();1040auto res = b.create<cir::ConstantOp>(loc, builder.getTrueAttr());1041b.create<cir::YieldOp>(loc, res.getRes());1042},1043/*falseBuilder*/1044[&](mlir::OpBuilder &b, mlir::Location loc) {1045CIRGenFunction::LexicalScope lexScope{cgf, loc,1046b.getInsertionBlock()};1047cgf.curLexScope->setAsTernary();1048b.create<cir::YieldOp>(loc, cgf.evaluateExprAsBool(e->getRHS()));1049});10501051return maybePromoteBoolResult(resOp.getResult(), resTy);1052}1053};10541055LValue ScalarExprEmitter::emitCompoundAssignLValue(1056const CompoundAssignOperator *e,1057mlir::Value (ScalarExprEmitter::*func)(const BinOpInfo &),1058mlir::Value &result) {1059QualType lhsTy = e->getLHS()->getType();1060BinOpInfo opInfo;10611062if (e->getComputationResultType()->isAnyComplexType()) {1063cgf.cgm.errorNYI(result.getLoc(), "complex lvalue assign");1064return LValue();1065}10661067// Emit the RHS first. __block variables need to have the rhs evaluated1068// first, plus this should improve codegen a little.10691070QualType promotionTypeCR = getPromotionType(e->getComputationResultType());1071if (promotionTypeCR.isNull())1072promotionTypeCR = e->getComputationResultType();10731074QualType promotionTypeLHS = getPromotionType(e->getComputationLHSType());1075QualType promotionTypeRHS = getPromotionType(e->getRHS()->getType());10761077if (!promotionTypeRHS.isNull())1078opInfo.rhs = cgf.emitPromotedScalarExpr(e->getRHS(), promotionTypeRHS);1079else1080opInfo.rhs = Visit(e->getRHS());10811082opInfo.fullType = promotionTypeCR;1083opInfo.compType = opInfo.fullType;1084if (const auto *vecType = dyn_cast_or_null<VectorType>(opInfo.fullType))1085opInfo.compType = vecType->getElementType();1086opInfo.opcode = e->getOpcode();1087opInfo.fpfeatures = e->getFPFeaturesInEffect(cgf.getLangOpts());1088opInfo.e = e;1089opInfo.loc = e->getSourceRange();10901091// Load/convert the LHS1092LValue lhsLV = cgf.emitLValue(e->getLHS());10931094if (lhsTy->getAs<AtomicType>()) {1095cgf.cgm.errorNYI(result.getLoc(), "atomic lvalue assign");1096return LValue();1097}10981099opInfo.lhs = emitLoadOfLValue(lhsLV, e->getExprLoc());11001101CIRGenFunction::SourceLocRAIIObject sourceloc{1102cgf, cgf.getLoc(e->getSourceRange())};1103SourceLocation loc = e->getExprLoc();1104if (!promotionTypeLHS.isNull())1105opInfo.lhs = emitScalarConversion(opInfo.lhs, lhsTy, promotionTypeLHS, loc);1106else1107opInfo.lhs = emitScalarConversion(opInfo.lhs, lhsTy,1108e->getComputationLHSType(), loc);11091110// Expand the binary operator.1111result = (this->*func)(opInfo);11121113// Convert the result back to the LHS type,1114// potentially with Implicit Conversion sanitizer check.1115result = emitScalarConversion(result, promotionTypeCR, lhsTy, loc,1116ScalarConversionOpts(cgf.sanOpts));11171118// Store the result value into the LHS lvalue. Bit-fields are handled1119// specially because the result is altered by the store, i.e., [C99 6.5.16p1]1120// 'An assignment expression has the value of the left operand after the1121// assignment...'.1122if (lhsLV.isBitField())1123cgf.cgm.errorNYI(e->getSourceRange(), "store through bitfield lvalue");1124else1125cgf.emitStoreThroughLValue(RValue::get(result), lhsLV);11261127if (cgf.getLangOpts().OpenMP)1128cgf.cgm.errorNYI(e->getSourceRange(), "openmp");11291130return lhsLV;1131}11321133mlir::Value ScalarExprEmitter::emitPromoted(const Expr *e,1134QualType promotionType) {1135e = e->IgnoreParens();1136if (const auto *bo = dyn_cast<BinaryOperator>(e)) {1137switch (bo->getOpcode()) {1138#define HANDLE_BINOP(OP) \1139case BO_##OP: \1140return emit##OP(emitBinOps(bo, promotionType));1141HANDLE_BINOP(Add)1142HANDLE_BINOP(Sub)1143HANDLE_BINOP(Mul)1144HANDLE_BINOP(Div)1145#undef HANDLE_BINOP1146default:1147break;1148}1149} else if (isa<UnaryOperator>(e)) {1150cgf.cgm.errorNYI(e->getSourceRange(), "unary operators");1151return {};1152}1153mlir::Value result = Visit(const_cast<Expr *>(e));1154if (result) {1155if (!promotionType.isNull())1156return emitPromotedValue(result, promotionType);1157return emitUnPromotedValue(result, e->getType());1158}1159return result;1160}11611162mlir::Value ScalarExprEmitter::emitCompoundAssign(1163const CompoundAssignOperator *e,1164mlir::Value (ScalarExprEmitter::*func)(const BinOpInfo &)) {11651166bool ignore = std::exchange(ignoreResultAssign, false);1167mlir::Value rhs;1168LValue lhs = emitCompoundAssignLValue(e, func, rhs);11691170// If the result is clearly ignored, return now.1171if (ignore)1172return {};11731174// The result of an assignment in C is the assigned r-value.1175if (!cgf.getLangOpts().CPlusPlus)1176return rhs;11771178// If the lvalue is non-volatile, return the computed value of the assignment.1179if (!lhs.isVolatile())1180return rhs;11811182// Otherwise, reload the value.1183return emitLoadOfLValue(lhs, e->getExprLoc());1184}11851186} // namespace11871188LValue1189CIRGenFunction::emitCompoundAssignmentLValue(const CompoundAssignOperator *e) {1190ScalarExprEmitter emitter(*this, builder);1191mlir::Value result;1192switch (e->getOpcode()) {1193#define COMPOUND_OP(Op) \1194case BO_##Op##Assign: \1195return emitter.emitCompoundAssignLValue(e, &ScalarExprEmitter::emit##Op, \1196result)1197COMPOUND_OP(Mul);1198COMPOUND_OP(Div);1199COMPOUND_OP(Rem);1200COMPOUND_OP(Add);1201COMPOUND_OP(Sub);1202COMPOUND_OP(Shl);1203COMPOUND_OP(Shr);1204COMPOUND_OP(And);1205COMPOUND_OP(Xor);1206COMPOUND_OP(Or);1207#undef COMPOUND_OP12081209case BO_PtrMemD:1210case BO_PtrMemI:1211case BO_Mul:1212case BO_Div:1213case BO_Rem:1214case BO_Add:1215case BO_Sub:1216case BO_Shl:1217case BO_Shr:1218case BO_LT:1219case BO_GT:1220case BO_LE:1221case BO_GE:1222case BO_EQ:1223case BO_NE:1224case BO_Cmp:1225case BO_And:1226case BO_Xor:1227case BO_Or:1228case BO_LAnd:1229case BO_LOr:1230case BO_Assign:1231case BO_Comma:1232llvm_unreachable("Not valid compound assignment operators");1233}1234llvm_unreachable("Unhandled compound assignment operator");1235}12361237/// Emit the computation of the specified expression of scalar type.1238mlir::Value CIRGenFunction::emitScalarExpr(const Expr *e) {1239assert(e && hasScalarEvaluationKind(e->getType()) &&1240"Invalid scalar expression to emit");12411242return ScalarExprEmitter(*this, builder).Visit(const_cast<Expr *>(e));1243}12441245mlir::Value CIRGenFunction::emitPromotedScalarExpr(const Expr *e,1246QualType promotionType) {1247if (!promotionType.isNull())1248return ScalarExprEmitter(*this, builder).emitPromoted(e, promotionType);1249return ScalarExprEmitter(*this, builder).Visit(const_cast<Expr *>(e));1250}12511252[[maybe_unused]] static bool mustVisitNullValue(const Expr *e) {1253// If a null pointer expression's type is the C++0x nullptr_t and1254// the expression is not a simple literal, it must be evaluated1255// for its potential side effects.1256if (isa<IntegerLiteral>(e) || isa<CXXNullPtrLiteralExpr>(e))1257return false;1258return e->getType()->isNullPtrType();1259}12601261/// If \p e is a widened promoted integer, get its base (unpromoted) type.1262static std::optional<QualType>1263getUnwidenedIntegerType(const ASTContext &astContext, const Expr *e) {1264const Expr *base = e->IgnoreImpCasts();1265if (e == base)1266return std::nullopt;12671268QualType baseTy = base->getType();1269if (!astContext.isPromotableIntegerType(baseTy) ||1270astContext.getTypeSize(baseTy) >= astContext.getTypeSize(e->getType()))1271return std::nullopt;12721273return baseTy;1274}12751276/// Check if \p e is a widened promoted integer.1277[[maybe_unused]] static bool isWidenedIntegerOp(const ASTContext &astContext,1278const Expr *e) {1279return getUnwidenedIntegerType(astContext, e).has_value();1280}12811282/// Check if we can skip the overflow check for \p Op.1283[[maybe_unused]] static bool canElideOverflowCheck(const ASTContext &astContext,1284const BinOpInfo &op) {1285assert((isa<UnaryOperator>(op.e) || isa<BinaryOperator>(op.e)) &&1286"Expected a unary or binary operator");12871288// If the binop has constant inputs and we can prove there is no overflow,1289// we can elide the overflow check.1290if (!op.mayHaveIntegerOverflow())1291return true;12921293// If a unary op has a widened operand, the op cannot overflow.1294if (const auto *uo = dyn_cast<UnaryOperator>(op.e))1295return !uo->canOverflow();12961297// We usually don't need overflow checks for binops with widened operands.1298// Multiplication with promoted unsigned operands is a special case.1299const auto *bo = cast<BinaryOperator>(op.e);1300std::optional<QualType> optionalLHSTy =1301getUnwidenedIntegerType(astContext, bo->getLHS());1302if (!optionalLHSTy)1303return false;13041305std::optional<QualType> optionalRHSTy =1306getUnwidenedIntegerType(astContext, bo->getRHS());1307if (!optionalRHSTy)1308return false;13091310QualType lhsTy = *optionalLHSTy;1311QualType rhsTy = *optionalRHSTy;13121313// This is the simple case: binops without unsigned multiplication, and with1314// widened operands. No overflow check is needed here.1315if ((op.opcode != BO_Mul && op.opcode != BO_MulAssign) ||1316!lhsTy->isUnsignedIntegerType() || !rhsTy->isUnsignedIntegerType())1317return true;13181319// For unsigned multiplication the overflow check can be elided if either one1320// of the unpromoted types are less than half the size of the promoted type.1321unsigned promotedSize = astContext.getTypeSize(op.e->getType());1322return (2 * astContext.getTypeSize(lhsTy)) < promotedSize ||1323(2 * astContext.getTypeSize(rhsTy)) < promotedSize;1324}13251326/// Emit pointer + index arithmetic.1327static mlir::Value emitPointerArithmetic(CIRGenFunction &cgf,1328const BinOpInfo &op,1329bool isSubtraction) {1330// Must have binary (not unary) expr here. Unary pointer1331// increment/decrement doesn't use this path.1332const BinaryOperator *expr = cast<BinaryOperator>(op.e);13331334mlir::Value pointer = op.lhs;1335Expr *pointerOperand = expr->getLHS();1336mlir::Value index = op.rhs;1337Expr *indexOperand = expr->getRHS();13381339// In the case of subtraction, the FE has ensured that the LHS is always the1340// pointer. However, addition can have the pointer on either side. We will1341// always have a pointer operand and an integer operand, so if the LHS wasn't1342// a pointer, we need to swap our values.1343if (!isSubtraction && !mlir::isa<cir::PointerType>(pointer.getType())) {1344std::swap(pointer, index);1345std::swap(pointerOperand, indexOperand);1346}1347assert(mlir::isa<cir::PointerType>(pointer.getType()) &&1348"Need a pointer operand");1349assert(mlir::isa<cir::IntType>(index.getType()) && "Need an integer operand");13501351// Some versions of glibc and gcc use idioms (particularly in their malloc1352// routines) that add a pointer-sized integer (known to be a pointer value)1353// to a null pointer in order to cast the value back to an integer or as1354// part of a pointer alignment algorithm. This is undefined behavior, but1355// we'd like to be able to compile programs that use it.1356//1357// Normally, we'd generate a GEP with a null-pointer base here in response1358// to that code, but it's also UB to dereference a pointer created that1359// way. Instead (as an acknowledged hack to tolerate the idiom) we will1360// generate a direct cast of the integer value to a pointer.1361//1362// The idiom (p = nullptr + N) is not met if any of the following are true:1363//1364// The operation is subtraction.1365// The index is not pointer-sized.1366// The pointer type is not byte-sized.1367//1368if (BinaryOperator::isNullPointerArithmeticExtension(1369cgf.getContext(), op.opcode, expr->getLHS(), expr->getRHS()))1370return cgf.getBuilder().createIntToPtr(index, pointer.getType());13711372// Differently from LLVM codegen, ABI bits for index sizes is handled during1373// LLVM lowering.13741375// If this is subtraction, negate the index.1376if (isSubtraction)1377index = cgf.getBuilder().createNeg(index);13781379assert(!cir::MissingFeatures::sanitizers());13801381const PointerType *pointerType =1382pointerOperand->getType()->getAs<PointerType>();1383if (!pointerType) {1384cgf.cgm.errorNYI("Objective-C:pointer arithmetic with non-pointer type");1385return nullptr;1386}13871388QualType elementType = pointerType->getPointeeType();1389if (cgf.getContext().getAsVariableArrayType(elementType)) {1390cgf.cgm.errorNYI("variable array type");1391return nullptr;1392}13931394if (elementType->isVoidType() || elementType->isFunctionType()) {1395cgf.cgm.errorNYI("void* or function pointer arithmetic");1396return nullptr;1397}13981399assert(!cir::MissingFeatures::sanitizers());1400return cgf.getBuilder().create<cir::PtrStrideOp>(1401cgf.getLoc(op.e->getExprLoc()), pointer.getType(), pointer, index);1402}14031404mlir::Value ScalarExprEmitter::emitMul(const BinOpInfo &ops) {1405const mlir::Location loc = cgf.getLoc(ops.loc);1406if (ops.compType->isSignedIntegerOrEnumerationType()) {1407switch (cgf.getLangOpts().getSignedOverflowBehavior()) {1408case LangOptions::SOB_Defined:1409if (!cgf.sanOpts.has(SanitizerKind::SignedIntegerOverflow))1410return builder.createMul(loc, ops.lhs, ops.rhs);1411[[fallthrough]];1412case LangOptions::SOB_Undefined:1413if (!cgf.sanOpts.has(SanitizerKind::SignedIntegerOverflow))1414return builder.createNSWMul(loc, ops.lhs, ops.rhs);1415[[fallthrough]];1416case LangOptions::SOB_Trapping:1417if (canElideOverflowCheck(cgf.getContext(), ops))1418return builder.createNSWMul(loc, ops.lhs, ops.rhs);1419cgf.cgm.errorNYI("sanitizers");1420}1421}1422if (ops.fullType->isConstantMatrixType()) {1423assert(!cir::MissingFeatures::matrixType());1424cgf.cgm.errorNYI("matrix types");1425return nullptr;1426}1427if (ops.compType->isUnsignedIntegerType() &&1428cgf.sanOpts.has(SanitizerKind::UnsignedIntegerOverflow) &&1429!canElideOverflowCheck(cgf.getContext(), ops))1430cgf.cgm.errorNYI("unsigned int overflow sanitizer");14311432if (cir::isFPOrVectorOfFPType(ops.lhs.getType())) {1433assert(!cir::MissingFeatures::cgFPOptionsRAII());1434return builder.createFMul(loc, ops.lhs, ops.rhs);1435}14361437if (ops.isFixedPointOp()) {1438assert(!cir::MissingFeatures::fixedPointType());1439cgf.cgm.errorNYI("fixed point");1440return nullptr;1441}14421443return builder.create<cir::BinOp>(cgf.getLoc(ops.loc),1444cgf.convertType(ops.fullType),1445cir::BinOpKind::Mul, ops.lhs, ops.rhs);1446}1447mlir::Value ScalarExprEmitter::emitDiv(const BinOpInfo &ops) {1448return builder.create<cir::BinOp>(cgf.getLoc(ops.loc),1449cgf.convertType(ops.fullType),1450cir::BinOpKind::Div, ops.lhs, ops.rhs);1451}1452mlir::Value ScalarExprEmitter::emitRem(const BinOpInfo &ops) {1453return builder.create<cir::BinOp>(cgf.getLoc(ops.loc),1454cgf.convertType(ops.fullType),1455cir::BinOpKind::Rem, ops.lhs, ops.rhs);1456}14571458mlir::Value ScalarExprEmitter::emitAdd(const BinOpInfo &ops) {1459if (mlir::isa<cir::PointerType>(ops.lhs.getType()) ||1460mlir::isa<cir::PointerType>(ops.rhs.getType()))1461return emitPointerArithmetic(cgf, ops, /*isSubtraction=*/false);14621463const mlir::Location loc = cgf.getLoc(ops.loc);1464if (ops.compType->isSignedIntegerOrEnumerationType()) {1465switch (cgf.getLangOpts().getSignedOverflowBehavior()) {1466case LangOptions::SOB_Defined:1467if (!cgf.sanOpts.has(SanitizerKind::SignedIntegerOverflow))1468return builder.createAdd(loc, ops.lhs, ops.rhs);1469[[fallthrough]];1470case LangOptions::SOB_Undefined:1471if (!cgf.sanOpts.has(SanitizerKind::SignedIntegerOverflow))1472return builder.createNSWAdd(loc, ops.lhs, ops.rhs);1473[[fallthrough]];1474case LangOptions::SOB_Trapping:1475if (canElideOverflowCheck(cgf.getContext(), ops))1476return builder.createNSWAdd(loc, ops.lhs, ops.rhs);1477cgf.cgm.errorNYI("sanitizers");1478}1479}1480if (ops.fullType->isConstantMatrixType()) {1481assert(!cir::MissingFeatures::matrixType());1482cgf.cgm.errorNYI("matrix types");1483return nullptr;1484}14851486if (ops.compType->isUnsignedIntegerType() &&1487cgf.sanOpts.has(SanitizerKind::UnsignedIntegerOverflow) &&1488!canElideOverflowCheck(cgf.getContext(), ops))1489cgf.cgm.errorNYI("unsigned int overflow sanitizer");14901491if (cir::isFPOrVectorOfFPType(ops.lhs.getType())) {1492assert(!cir::MissingFeatures::cgFPOptionsRAII());1493return builder.createFAdd(loc, ops.lhs, ops.rhs);1494}14951496if (ops.isFixedPointOp()) {1497assert(!cir::MissingFeatures::fixedPointType());1498cgf.cgm.errorNYI("fixed point");1499return {};1500}15011502return builder.create<cir::BinOp>(loc, cgf.convertType(ops.fullType),1503cir::BinOpKind::Add, ops.lhs, ops.rhs);1504}15051506mlir::Value ScalarExprEmitter::emitSub(const BinOpInfo &ops) {1507const mlir::Location loc = cgf.getLoc(ops.loc);1508// The LHS is always a pointer if either side is.1509if (!mlir::isa<cir::PointerType>(ops.lhs.getType())) {1510if (ops.compType->isSignedIntegerOrEnumerationType()) {1511switch (cgf.getLangOpts().getSignedOverflowBehavior()) {1512case LangOptions::SOB_Defined: {1513if (!cgf.sanOpts.has(SanitizerKind::SignedIntegerOverflow))1514return builder.createSub(loc, ops.lhs, ops.rhs);1515[[fallthrough]];1516}1517case LangOptions::SOB_Undefined:1518if (!cgf.sanOpts.has(SanitizerKind::SignedIntegerOverflow))1519return builder.createNSWSub(loc, ops.lhs, ops.rhs);1520[[fallthrough]];1521case LangOptions::SOB_Trapping:1522if (canElideOverflowCheck(cgf.getContext(), ops))1523return builder.createNSWSub(loc, ops.lhs, ops.rhs);1524cgf.cgm.errorNYI("sanitizers");1525}1526}15271528if (ops.fullType->isConstantMatrixType()) {1529assert(!cir::MissingFeatures::matrixType());1530cgf.cgm.errorNYI("matrix types");1531return nullptr;1532}15331534if (ops.compType->isUnsignedIntegerType() &&1535cgf.sanOpts.has(SanitizerKind::UnsignedIntegerOverflow) &&1536!canElideOverflowCheck(cgf.getContext(), ops))1537cgf.cgm.errorNYI("unsigned int overflow sanitizer");15381539if (cir::isFPOrVectorOfFPType(ops.lhs.getType())) {1540assert(!cir::MissingFeatures::cgFPOptionsRAII());1541return builder.createFSub(loc, ops.lhs, ops.rhs);1542}15431544if (ops.isFixedPointOp()) {1545assert(!cir::MissingFeatures::fixedPointType());1546cgf.cgm.errorNYI("fixed point");1547return {};1548}15491550return builder.create<cir::BinOp>(cgf.getLoc(ops.loc),1551cgf.convertType(ops.fullType),1552cir::BinOpKind::Sub, ops.lhs, ops.rhs);1553}15541555// If the RHS is not a pointer, then we have normal pointer1556// arithmetic.1557if (!mlir::isa<cir::PointerType>(ops.rhs.getType()))1558return emitPointerArithmetic(cgf, ops, /*isSubtraction=*/true);15591560// Otherwise, this is a pointer subtraction15611562// Do the raw subtraction part.1563//1564// TODO(cir): note for LLVM lowering out of this; when expanding this into1565// LLVM we shall take VLA's, division by element size, etc.1566//1567// See more in `EmitSub` in CGExprScalar.cpp.1568assert(!cir::MissingFeatures::ptrDiffOp());1569cgf.cgm.errorNYI("ptrdiff");1570return {};1571}15721573mlir::Value ScalarExprEmitter::emitShl(const BinOpInfo &ops) {1574// TODO: This misses out on the sanitizer check below.1575if (ops.isFixedPointOp()) {1576assert(cir::MissingFeatures::fixedPointType());1577cgf.cgm.errorNYI("fixed point");1578return {};1579}15801581// CIR accepts shift between different types, meaning nothing special1582// to be done here. OTOH, LLVM requires the LHS and RHS to be the same type:1583// promote or truncate the RHS to the same size as the LHS.15841585bool sanitizeSignedBase = cgf.sanOpts.has(SanitizerKind::ShiftBase) &&1586ops.compType->hasSignedIntegerRepresentation() &&1587!cgf.getLangOpts().isSignedOverflowDefined() &&1588!cgf.getLangOpts().CPlusPlus20;1589bool sanitizeUnsignedBase =1590cgf.sanOpts.has(SanitizerKind::UnsignedShiftBase) &&1591ops.compType->hasUnsignedIntegerRepresentation();1592bool sanitizeBase = sanitizeSignedBase || sanitizeUnsignedBase;1593bool sanitizeExponent = cgf.sanOpts.has(SanitizerKind::ShiftExponent);15941595// OpenCL 6.3j: shift values are effectively % word size of LHS.1596if (cgf.getLangOpts().OpenCL)1597cgf.cgm.errorNYI("opencl");1598else if ((sanitizeBase || sanitizeExponent) &&1599mlir::isa<cir::IntType>(ops.lhs.getType()))1600cgf.cgm.errorNYI("sanitizers");16011602return builder.createShiftLeft(cgf.getLoc(ops.loc), ops.lhs, ops.rhs);1603}16041605mlir::Value ScalarExprEmitter::emitShr(const BinOpInfo &ops) {1606// TODO: This misses out on the sanitizer check below.1607if (ops.isFixedPointOp()) {1608assert(cir::MissingFeatures::fixedPointType());1609cgf.cgm.errorNYI("fixed point");1610return {};1611}16121613// CIR accepts shift between different types, meaning nothing special1614// to be done here. OTOH, LLVM requires the LHS and RHS to be the same type:1615// promote or truncate the RHS to the same size as the LHS.16161617// OpenCL 6.3j: shift values are effectively % word size of LHS.1618if (cgf.getLangOpts().OpenCL)1619cgf.cgm.errorNYI("opencl");1620else if (cgf.sanOpts.has(SanitizerKind::ShiftExponent) &&1621mlir::isa<cir::IntType>(ops.lhs.getType()))1622cgf.cgm.errorNYI("sanitizers");16231624// Note that we don't need to distinguish unsigned treatment at this1625// point since it will be handled later by LLVM lowering.1626return builder.createShiftRight(cgf.getLoc(ops.loc), ops.lhs, ops.rhs);1627}16281629mlir::Value ScalarExprEmitter::emitAnd(const BinOpInfo &ops) {1630return builder.create<cir::BinOp>(cgf.getLoc(ops.loc),1631cgf.convertType(ops.fullType),1632cir::BinOpKind::And, ops.lhs, ops.rhs);1633}1634mlir::Value ScalarExprEmitter::emitXor(const BinOpInfo &ops) {1635return builder.create<cir::BinOp>(cgf.getLoc(ops.loc),1636cgf.convertType(ops.fullType),1637cir::BinOpKind::Xor, ops.lhs, ops.rhs);1638}1639mlir::Value ScalarExprEmitter::emitOr(const BinOpInfo &ops) {1640return builder.create<cir::BinOp>(cgf.getLoc(ops.loc),1641cgf.convertType(ops.fullType),1642cir::BinOpKind::Or, ops.lhs, ops.rhs);1643}16441645// Emit code for an explicit or implicit cast. Implicit1646// casts have to handle a more broad range of conversions than explicit1647// casts, as they handle things like function to ptr-to-function decay1648// etc.1649mlir::Value ScalarExprEmitter::VisitCastExpr(CastExpr *ce) {1650Expr *subExpr = ce->getSubExpr();1651QualType destTy = ce->getType();1652CastKind kind = ce->getCastKind();16531654// These cases are generally not written to ignore the result of evaluating1655// their sub-expressions, so we clear this now.1656ignoreResultAssign = false;16571658switch (kind) {1659case clang::CK_Dependent:1660llvm_unreachable("dependent cast kind in CIR gen!");1661case clang::CK_BuiltinFnToFnPtr:1662llvm_unreachable("builtin functions are handled elsewhere");16631664case CK_CPointerToObjCPointerCast:1665case CK_BlockPointerToObjCPointerCast:1666case CK_AnyPointerToBlockPointerCast:1667case CK_BitCast: {1668mlir::Value src = Visit(const_cast<Expr *>(subExpr));1669mlir::Type dstTy = cgf.convertType(destTy);16701671assert(!cir::MissingFeatures::addressSpace());16721673if (cgf.sanOpts.has(SanitizerKind::CFIUnrelatedCast))1674cgf.getCIRGenModule().errorNYI(subExpr->getSourceRange(),1675"sanitizer support");16761677if (cgf.cgm.getCodeGenOpts().StrictVTablePointers)1678cgf.getCIRGenModule().errorNYI(subExpr->getSourceRange(),1679"strict vtable pointers");16801681// Update heapallocsite metadata when there is an explicit pointer cast.1682assert(!cir::MissingFeatures::addHeapAllocSiteMetadata());16831684// If Src is a fixed vector and Dst is a scalable vector, and both have the1685// same element type, use the llvm.vector.insert intrinsic to perform the1686// bitcast.1687assert(!cir::MissingFeatures::scalableVectors());16881689// If Src is a scalable vector and Dst is a fixed vector, and both have the1690// same element type, use the llvm.vector.extract intrinsic to perform the1691// bitcast.1692assert(!cir::MissingFeatures::scalableVectors());16931694// Perform VLAT <-> VLST bitcast through memory.1695// TODO: since the llvm.experimental.vector.{insert,extract} intrinsics1696// require the element types of the vectors to be the same, we1697// need to keep this around for bitcasts between VLAT <-> VLST where1698// the element types of the vectors are not the same, until we figure1699// out a better way of doing these casts.1700assert(!cir::MissingFeatures::scalableVectors());17011702return cgf.getBuilder().createBitcast(cgf.getLoc(subExpr->getSourceRange()),1703src, dstTy);1704}17051706case CK_AtomicToNonAtomic: {1707cgf.getCIRGenModule().errorNYI(subExpr->getSourceRange(),1708"CastExpr: ", ce->getCastKindName());1709mlir::Location loc = cgf.getLoc(subExpr->getSourceRange());1710return cgf.createDummyValue(loc, destTy);1711}1712case CK_NonAtomicToAtomic:1713case CK_UserDefinedConversion:1714return Visit(const_cast<Expr *>(subExpr));1715case CK_NoOp: {1716auto v = Visit(const_cast<Expr *>(subExpr));1717if (v) {1718// CK_NoOp can model a pointer qualification conversion, which can remove1719// an array bound and change the IR type.1720// FIXME: Once pointee types are removed from IR, remove this.1721mlir::Type t = cgf.convertType(destTy);1722if (t != v.getType())1723cgf.getCIRGenModule().errorNYI("pointer qualification conversion");1724}1725return v;1726}17271728case CK_ArrayToPointerDecay:1729return cgf.emitArrayToPointerDecay(subExpr).getPointer();17301731case CK_NullToPointer: {1732if (mustVisitNullValue(subExpr))1733cgf.emitIgnoredExpr(subExpr);17341735// Note that DestTy is used as the MLIR type instead of a custom1736// nullptr type.1737mlir::Type ty = cgf.convertType(destTy);1738return builder.getNullPtr(ty, cgf.getLoc(subExpr->getExprLoc()));1739}17401741case CK_LValueToRValue:1742assert(cgf.getContext().hasSameUnqualifiedType(subExpr->getType(), destTy));1743assert(subExpr->isGLValue() && "lvalue-to-rvalue applied to r-value!");1744return Visit(const_cast<Expr *>(subExpr));17451746case CK_IntegralCast: {1747ScalarConversionOpts opts;1748if (auto *ice = dyn_cast<ImplicitCastExpr>(ce)) {1749if (!ice->isPartOfExplicitCast())1750opts = ScalarConversionOpts(cgf.sanOpts);1751}1752return emitScalarConversion(Visit(subExpr), subExpr->getType(), destTy,1753ce->getExprLoc(), opts);1754}17551756case CK_FloatingRealToComplex:1757case CK_FloatingComplexCast:1758case CK_IntegralRealToComplex:1759case CK_IntegralComplexCast:1760case CK_IntegralComplexToFloatingComplex:1761case CK_FloatingComplexToIntegralComplex:1762llvm_unreachable("scalar cast to non-scalar value");17631764case CK_PointerToIntegral: {1765assert(!destTy->isBooleanType() && "bool should use PointerToBool");1766if (cgf.cgm.getCodeGenOpts().StrictVTablePointers)1767cgf.getCIRGenModule().errorNYI(subExpr->getSourceRange(),1768"strict vtable pointers");1769return builder.createPtrToInt(Visit(subExpr), cgf.convertType(destTy));1770}1771case CK_ToVoid:1772cgf.emitIgnoredExpr(subExpr);1773return {};17741775case CK_IntegralToFloating:1776case CK_FloatingToIntegral:1777case CK_FloatingCast:1778case CK_FixedPointToFloating:1779case CK_FloatingToFixedPoint: {1780if (kind == CK_FixedPointToFloating || kind == CK_FloatingToFixedPoint) {1781cgf.getCIRGenModule().errorNYI(subExpr->getSourceRange(),1782"fixed point casts");1783return {};1784}1785assert(!cir::MissingFeatures::cgFPOptionsRAII());1786return emitScalarConversion(Visit(subExpr), subExpr->getType(), destTy,1787ce->getExprLoc());1788}17891790case CK_IntegralToBoolean:1791return emitIntToBoolConversion(Visit(subExpr),1792cgf.getLoc(ce->getSourceRange()));17931794case CK_PointerToBoolean:1795return emitPointerToBoolConversion(Visit(subExpr), subExpr->getType());1796case CK_FloatingToBoolean:1797return emitFloatToBoolConversion(Visit(subExpr),1798cgf.getLoc(subExpr->getExprLoc()));1799case CK_MemberPointerToBoolean: {1800mlir::Value memPtr = Visit(subExpr);1801return builder.createCast(cgf.getLoc(ce->getSourceRange()),1802cir::CastKind::member_ptr_to_bool, memPtr,1803cgf.convertType(destTy));1804}18051806case CK_VectorSplat: {1807// Create a vector object and fill all elements with the same scalar value.1808assert(destTy->isVectorType() && "CK_VectorSplat to non-vector type");1809return builder.create<cir::VecSplatOp>(1810cgf.getLoc(subExpr->getSourceRange()), cgf.convertType(destTy),1811Visit(subExpr));1812}18131814default:1815cgf.getCIRGenModule().errorNYI(subExpr->getSourceRange(),1816"CastExpr: ", ce->getCastKindName());1817}1818return {};1819}18201821mlir::Value ScalarExprEmitter::VisitCallExpr(const CallExpr *e) {1822if (e->getCallReturnType(cgf.getContext())->isReferenceType())1823return emitLoadOfLValue(e);18241825auto v = cgf.emitCallExpr(e).getValue();1826assert(!cir::MissingFeatures::emitLValueAlignmentAssumption());1827return v;1828}18291830mlir::Value ScalarExprEmitter::VisitMemberExpr(MemberExpr *e) {1831// TODO(cir): The classic codegen calls tryEmitAsConstant() here. Folding1832// constants sound like work for MLIR optimizers, but we'll keep an assertion1833// for now.1834assert(!cir::MissingFeatures::tryEmitAsConstant());1835Expr::EvalResult result;1836if (e->EvaluateAsInt(result, cgf.getContext(), Expr::SE_AllowSideEffects)) {1837cgf.cgm.errorNYI(e->getSourceRange(), "Constant interger member expr");1838// Fall through to emit this as a non-constant access.1839}1840return emitLoadOfLValue(e);1841}18421843mlir::Value ScalarExprEmitter::VisitInitListExpr(InitListExpr *e) {1844const unsigned numInitElements = e->getNumInits();18451846if (e->hadArrayRangeDesignator()) {1847cgf.cgm.errorNYI(e->getSourceRange(), "ArrayRangeDesignator");1848return {};1849}18501851if (e->getType()->isVectorType()) {1852const auto vectorType =1853mlir::cast<cir::VectorType>(cgf.convertType(e->getType()));18541855SmallVector<mlir::Value, 16> elements;1856for (Expr *init : e->inits()) {1857elements.push_back(Visit(init));1858}18591860// Zero-initialize any remaining values.1861if (numInitElements < vectorType.getSize()) {1862const mlir::Value zeroValue = cgf.getBuilder().getNullValue(1863vectorType.getElementType(), cgf.getLoc(e->getSourceRange()));1864std::fill_n(std::back_inserter(elements),1865vectorType.getSize() - numInitElements, zeroValue);1866}18671868return cgf.getBuilder().create<cir::VecCreateOp>(1869cgf.getLoc(e->getSourceRange()), vectorType, elements);1870}18711872if (numInitElements == 0) {1873cgf.cgm.errorNYI(e->getSourceRange(),1874"InitListExpr Non VectorType with 0 init elements");1875return {};1876}18771878return Visit(e->getInit(0));1879}18801881mlir::Value CIRGenFunction::emitScalarConversion(mlir::Value src,1882QualType srcTy, QualType dstTy,1883SourceLocation loc) {1884assert(CIRGenFunction::hasScalarEvaluationKind(srcTy) &&1885CIRGenFunction::hasScalarEvaluationKind(dstTy) &&1886"Invalid scalar expression to emit");1887return ScalarExprEmitter(*this, builder)1888.emitScalarConversion(src, srcTy, dstTy, loc);1889}18901891mlir::Value ScalarExprEmitter::VisitUnaryLNot(const UnaryOperator *e) {1892// Perform vector logical not on comparison with zero vector.1893if (e->getType()->isVectorType() &&1894e->getType()->castAs<VectorType>()->getVectorKind() ==1895VectorKind::Generic) {1896assert(!cir::MissingFeatures::vectorType());1897cgf.cgm.errorNYI(e->getSourceRange(), "vector logical not");1898return {};1899}19001901// Compare operand to zero.1902mlir::Value boolVal = cgf.evaluateExprAsBool(e->getSubExpr());19031904// Invert value.1905boolVal = builder.createNot(boolVal);19061907// ZExt result to the expr type.1908return maybePromoteBoolResult(boolVal, cgf.convertType(e->getType()));1909}19101911mlir::Value ScalarExprEmitter::VisitUnaryReal(const UnaryOperator *e) {1912// TODO(cir): handle scalar promotion.1913Expr *op = e->getSubExpr();1914if (op->getType()->isAnyComplexType()) {1915// If it's an l-value, load through the appropriate subobject l-value.1916// Note that we have to ask `e` because `op` might be an l-value that1917// this won't work for, e.g. an Obj-C property.1918if (e->isGLValue()) {1919mlir::Location loc = cgf.getLoc(e->getExprLoc());1920mlir::Value complex = cgf.emitComplexExpr(op);1921return cgf.builder.createComplexReal(loc, complex);1922}19231924// Otherwise, calculate and project.1925cgf.cgm.errorNYI(e->getSourceRange(),1926"VisitUnaryReal calculate and project");1927}19281929return Visit(op);1930}19311932mlir::Value ScalarExprEmitter::VisitUnaryImag(const UnaryOperator *e) {1933// TODO(cir): handle scalar promotion.1934Expr *op = e->getSubExpr();1935if (op->getType()->isAnyComplexType()) {1936// If it's an l-value, load through the appropriate subobject l-value.1937// Note that we have to ask `e` because `op` might be an l-value that1938// this won't work for, e.g. an Obj-C property.1939if (e->isGLValue()) {1940mlir::Location loc = cgf.getLoc(e->getExprLoc());1941mlir::Value complex = cgf.emitComplexExpr(op);1942return cgf.builder.createComplexImag(loc, complex);1943}19441945// Otherwise, calculate and project.1946cgf.cgm.errorNYI(e->getSourceRange(),1947"VisitUnaryImag calculate and project");1948}19491950return Visit(op);1951}19521953/// Return the size or alignment of the type of argument of the sizeof1954/// expression as an integer.1955mlir::Value ScalarExprEmitter::VisitUnaryExprOrTypeTraitExpr(1956const UnaryExprOrTypeTraitExpr *e) {1957const QualType typeToSize = e->getTypeOfArgument();1958const mlir::Location loc = cgf.getLoc(e->getSourceRange());1959if (auto kind = e->getKind();1960kind == UETT_SizeOf || kind == UETT_DataSizeOf) {1961if (cgf.getContext().getAsVariableArrayType(typeToSize)) {1962cgf.getCIRGenModule().errorNYI(e->getSourceRange(),1963"sizeof operator for VariableArrayType",1964e->getStmtClassName());1965return builder.getConstant(1966loc, cir::IntAttr::get(cgf.cgm.UInt64Ty,1967llvm::APSInt(llvm::APInt(64, 1), true)));1968}1969} else if (e->getKind() == UETT_OpenMPRequiredSimdAlign) {1970cgf.getCIRGenModule().errorNYI(1971e->getSourceRange(), "sizeof operator for OpenMpRequiredSimdAlign",1972e->getStmtClassName());1973return builder.getConstant(1974loc, cir::IntAttr::get(cgf.cgm.UInt64Ty,1975llvm::APSInt(llvm::APInt(64, 1), true)));1976}19771978return builder.getConstant(1979loc, cir::IntAttr::get(cgf.cgm.UInt64Ty,1980e->EvaluateKnownConstInt(cgf.getContext())));1981}19821983/// Return true if the specified expression is cheap enough and side-effect-free1984/// enough to evaluate unconditionally instead of conditionally. This is used1985/// to convert control flow into selects in some cases.1986/// TODO(cir): can be shared with LLVM codegen.1987static bool isCheapEnoughToEvaluateUnconditionally(const Expr *e,1988CIRGenFunction &cgf) {1989// Anything that is an integer or floating point constant is fine.1990return e->IgnoreParens()->isEvaluatable(cgf.getContext());19911992// Even non-volatile automatic variables can't be evaluated unconditionally.1993// Referencing a thread_local may cause non-trivial initialization work to1994// occur. If we're inside a lambda and one of the variables is from the scope1995// outside the lambda, that function may have returned already. Reading its1996// locals is a bad idea. Also, these reads may introduce races there didn't1997// exist in the source-level program.1998}19992000mlir::Value ScalarExprEmitter::VisitAbstractConditionalOperator(2001const AbstractConditionalOperator *e) {2002CIRGenBuilderTy &builder = cgf.getBuilder();2003mlir::Location loc = cgf.getLoc(e->getSourceRange());2004ignoreResultAssign = false;20052006// Bind the common expression if necessary.2007CIRGenFunction::OpaqueValueMapping binding(cgf, e);20082009Expr *condExpr = e->getCond();2010Expr *lhsExpr = e->getTrueExpr();2011Expr *rhsExpr = e->getFalseExpr();20122013// If the condition constant folds and can be elided, try to avoid emitting2014// the condition and the dead arm.2015bool condExprBool;2016if (cgf.constantFoldsToBool(condExpr, condExprBool)) {2017Expr *live = lhsExpr, *dead = rhsExpr;2018if (!condExprBool)2019std::swap(live, dead);20202021// If the dead side doesn't have labels we need, just emit the Live part.2022if (!cgf.containsLabel(dead)) {2023if (condExprBool)2024assert(!cir::MissingFeatures::incrementProfileCounter());2025mlir::Value result = Visit(live);20262027// If the live part is a throw expression, it acts like it has a void2028// type, so evaluating it returns a null Value. However, a conditional2029// with non-void type must return a non-null Value.2030if (!result && !e->getType()->isVoidType()) {2031cgf.cgm.errorNYI(e->getSourceRange(),2032"throw expression in conditional operator");2033result = {};2034}20352036return result;2037}2038}20392040QualType condType = condExpr->getType();20412042// OpenCL: If the condition is a vector, we can treat this condition like2043// the select function.2044if ((cgf.getLangOpts().OpenCL && condType->isVectorType()) ||2045condType->isExtVectorType()) {2046assert(!cir::MissingFeatures::vectorType());2047cgf.cgm.errorNYI(e->getSourceRange(), "vector ternary op");2048}20492050if (condType->isVectorType() || condType->isSveVLSBuiltinType()) {2051if (!condType->isVectorType()) {2052assert(!cir::MissingFeatures::vecTernaryOp());2053cgf.cgm.errorNYI(loc, "TernaryOp for SVE vector");2054return {};2055}20562057mlir::Value condValue = Visit(condExpr);2058mlir::Value lhsValue = Visit(lhsExpr);2059mlir::Value rhsValue = Visit(rhsExpr);2060return builder.create<cir::VecTernaryOp>(loc, condValue, lhsValue,2061rhsValue);2062}20632064// If this is a really simple expression (like x ? 4 : 5), emit this as a2065// select instead of as control flow. We can only do this if it is cheap2066// and safe to evaluate the LHS and RHS unconditionally.2067if (isCheapEnoughToEvaluateUnconditionally(lhsExpr, cgf) &&2068isCheapEnoughToEvaluateUnconditionally(rhsExpr, cgf)) {2069bool lhsIsVoid = false;2070mlir::Value condV = cgf.evaluateExprAsBool(condExpr);2071assert(!cir::MissingFeatures::incrementProfileCounter());20722073mlir::Value lhs = Visit(lhsExpr);2074if (!lhs) {2075lhs = builder.getNullValue(cgf.VoidTy, loc);2076lhsIsVoid = true;2077}20782079mlir::Value rhs = Visit(rhsExpr);2080if (lhsIsVoid) {2081assert(!rhs && "lhs and rhs types must match");2082rhs = builder.getNullValue(cgf.VoidTy, loc);2083}20842085return builder.createSelect(loc, condV, lhs, rhs);2086}20872088mlir::Value condV = cgf.emitOpOnBoolExpr(loc, condExpr);2089CIRGenFunction::ConditionalEvaluation eval(cgf);2090SmallVector<mlir::OpBuilder::InsertPoint, 2> insertPoints{};2091mlir::Type yieldTy{};20922093auto emitBranch = [&](mlir::OpBuilder &b, mlir::Location loc, Expr *expr) {2094CIRGenFunction::LexicalScope lexScope{cgf, loc, b.getInsertionBlock()};2095cgf.curLexScope->setAsTernary();20962097assert(!cir::MissingFeatures::incrementProfileCounter());2098eval.beginEvaluation();2099mlir::Value branch = Visit(expr);2100eval.endEvaluation();21012102if (branch) {2103yieldTy = branch.getType();2104b.create<cir::YieldOp>(loc, branch);2105} else {2106// If LHS or RHS is a throw or void expression we need to patch2107// arms as to properly match yield types.2108insertPoints.push_back(b.saveInsertionPoint());2109}2110};21112112mlir::Value result = builder2113.create<cir::TernaryOp>(2114loc, condV,2115/*trueBuilder=*/2116[&](mlir::OpBuilder &b, mlir::Location loc) {2117emitBranch(b, loc, lhsExpr);2118},2119/*falseBuilder=*/2120[&](mlir::OpBuilder &b, mlir::Location loc) {2121emitBranch(b, loc, rhsExpr);2122})2123.getResult();21242125if (!insertPoints.empty()) {2126// If both arms are void, so be it.2127if (!yieldTy)2128yieldTy = cgf.VoidTy;21292130// Insert required yields.2131for (mlir::OpBuilder::InsertPoint &toInsert : insertPoints) {2132mlir::OpBuilder::InsertionGuard guard(builder);2133builder.restoreInsertionPoint(toInsert);21342135// Block does not return: build empty yield.2136if (mlir::isa<cir::VoidType>(yieldTy)) {2137builder.create<cir::YieldOp>(loc);2138} else { // Block returns: set null yield value.2139mlir::Value op0 = builder.getNullValue(yieldTy, loc);2140builder.create<cir::YieldOp>(loc, op0);2141}2142}2143}21442145return result;2146}21472148mlir::Value CIRGenFunction::emitScalarPrePostIncDec(const UnaryOperator *e,2149LValue lv, bool isInc,2150bool isPre) {2151return ScalarExprEmitter(*this, builder)2152.emitScalarPrePostIncDec(e, lv, isInc, isPre);2153}215421552156