@@ -58,6 +58,45 @@ static RValue emitBuiltinBitOp(CIRGenFunction &cgf, const CallExpr *e,
5858 return RValue::get (result);
5959}
6060
61+ namespace {
62+ struct WidthAndSignedness {
63+ unsigned width;
64+ bool isSigned;
65+ };
66+ } // namespace
67+
68+ static WidthAndSignedness
69+ getIntegerWidthAndSignedness (const clang::ASTContext &astContext,
70+ const clang::QualType type) {
71+ assert (type->isIntegerType () && " Given type is not an integer." );
72+ unsigned width = type->isBooleanType () ? 1
73+ : type->isBitIntType () ? astContext.getIntWidth (type)
74+ : astContext.getTypeInfo (type).Width ;
75+ bool isSigned = type->isSignedIntegerType ();
76+ return {width, isSigned};
77+ }
78+
79+ // Given one or more integer types, this function produces an integer type that
80+ // encompasses them: any value in one of the given types could be expressed in
81+ // the encompassing type.
82+ static struct WidthAndSignedness
83+ EncompassingIntegerType (ArrayRef<struct WidthAndSignedness > types) {
84+ assert (types.size () > 0 && " Empty list of types." );
85+
86+ // If any of the given types is signed, we must return a signed type.
87+ bool isSigned = llvm::any_of (types, [](const auto &t) { return t.isSigned ; });
88+
89+ // The encompassing type must have a width greater than or equal to the width
90+ // of the specified types. Additionally, if the encompassing type is signed,
91+ // its width must be strictly greater than the width of any unsigned types
92+ // given.
93+ unsigned width = 0 ;
94+ for (const auto &type : types)
95+ width = std::max (width, type.width + (isSigned && !type.isSigned ));
96+
97+ return {width, isSigned};
98+ }
99+
61100RValue CIRGenFunction::emitRotate (const CallExpr *e, bool isRotateLeft) {
62101 mlir::Value input = emitScalarExpr (e->getArg (0 ));
63102 mlir::Value amount = emitScalarExpr (e->getArg (1 ));
@@ -899,9 +938,85 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
899938 case Builtin::BI__builtin_subc:
900939 case Builtin::BI__builtin_subcl:
901940 case Builtin::BI__builtin_subcll:
941+ return errorBuiltinNYI (*this , e, builtinID);
942+
902943 case Builtin::BI__builtin_add_overflow:
903944 case Builtin::BI__builtin_sub_overflow:
904- case Builtin::BI__builtin_mul_overflow:
945+ case Builtin::BI__builtin_mul_overflow: {
946+ const clang::Expr *leftArg = e->getArg (0 );
947+ const clang::Expr *rightArg = e->getArg (1 );
948+ const clang::Expr *resultArg = e->getArg (2 );
949+
950+ clang::QualType resultQTy =
951+ resultArg->getType ()->castAs <clang::PointerType>()->getPointeeType ();
952+
953+ WidthAndSignedness leftInfo =
954+ getIntegerWidthAndSignedness (cgm.getASTContext (), leftArg->getType ());
955+ WidthAndSignedness rightInfo =
956+ getIntegerWidthAndSignedness (cgm.getASTContext (), rightArg->getType ());
957+ WidthAndSignedness resultInfo =
958+ getIntegerWidthAndSignedness (cgm.getASTContext (), resultQTy);
959+
960+ // Note we compute the encompassing type with the consideration to the
961+ // result type, so later in LLVM lowering we don't get redundant integral
962+ // extension casts.
963+ WidthAndSignedness encompassingInfo =
964+ EncompassingIntegerType ({leftInfo, rightInfo, resultInfo});
965+
966+ auto encompassingCIRTy = cir::IntType::get (
967+ &getMLIRContext (), encompassingInfo.width , encompassingInfo.isSigned );
968+ auto resultCIRTy = mlir::cast<cir::IntType>(cgm.convertType (resultQTy));
969+
970+ mlir::Value left = emitScalarExpr (leftArg);
971+ mlir::Value right = emitScalarExpr (rightArg);
972+ Address resultPtr = emitPointerWithAlignment (resultArg);
973+
974+ // Extend each operand to the encompassing type, if necessary.
975+ if (left.getType () != encompassingCIRTy)
976+ left =
977+ builder.createCast (cir::CastKind::integral, left, encompassingCIRTy);
978+ if (right.getType () != encompassingCIRTy)
979+ right =
980+ builder.createCast (cir::CastKind::integral, right, encompassingCIRTy);
981+
982+ // Perform the operation on the extended values.
983+ cir::BinOpOverflowKind opKind;
984+ switch (builtinID) {
985+ default :
986+ llvm_unreachable (" Unknown overflow builtin id." );
987+ case Builtin::BI__builtin_add_overflow:
988+ opKind = cir::BinOpOverflowKind::Add;
989+ break ;
990+ case Builtin::BI__builtin_sub_overflow:
991+ opKind = cir::BinOpOverflowKind::Sub;
992+ break ;
993+ case Builtin::BI__builtin_mul_overflow:
994+ opKind = cir::BinOpOverflowKind::Mul;
995+ break ;
996+ }
997+
998+ mlir::Location loc = getLoc (e->getSourceRange ());
999+ auto arithOp = cir::BinOpOverflowOp::create (builder, loc, resultCIRTy,
1000+ opKind, left, right);
1001+
1002+ // Here is a slight difference from the original clang CodeGen:
1003+ // - In the original clang CodeGen, the checked arithmetic result is
1004+ // first computed as a value of the encompassing type, and then it is
1005+ // truncated to the actual result type with a second overflow checking.
1006+ // - In CIRGen, the checked arithmetic operation directly produce the
1007+ // checked arithmetic result in its expected type.
1008+ //
1009+ // So we don't need a truncation and a second overflow checking here.
1010+
1011+ // Finally, store the result using the pointer.
1012+ bool isVolatile =
1013+ resultArg->getType ()->getPointeeType ().isVolatileQualified ();
1014+ builder.createStore (loc, emitToMemory (arithOp.getResult (), resultQTy),
1015+ resultPtr, isVolatile);
1016+
1017+ return RValue::get (arithOp.getOverflow ());
1018+ }
1019+
9051020 case Builtin::BI__builtin_uadd_overflow:
9061021 case Builtin::BI__builtin_uaddl_overflow:
9071022 case Builtin::BI__builtin_uaddll_overflow:
@@ -919,7 +1034,61 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
9191034 case Builtin::BI__builtin_ssubll_overflow:
9201035 case Builtin::BI__builtin_smul_overflow:
9211036 case Builtin::BI__builtin_smull_overflow:
922- case Builtin::BI__builtin_smulll_overflow:
1037+ case Builtin::BI__builtin_smulll_overflow: {
1038+ // Scalarize our inputs.
1039+ mlir::Value x = emitScalarExpr (e->getArg (0 ));
1040+ mlir::Value y = emitScalarExpr (e->getArg (1 ));
1041+
1042+ const clang::Expr *resultArg = e->getArg (2 );
1043+ Address resultPtr = emitPointerWithAlignment (resultArg);
1044+
1045+ // Decide which of the arithmetic operation we are lowering to:
1046+ cir::BinOpOverflowKind arithKind;
1047+ switch (builtinID) {
1048+ default :
1049+ llvm_unreachable (" Unknown overflow builtin id." );
1050+ case Builtin::BI__builtin_uadd_overflow:
1051+ case Builtin::BI__builtin_uaddl_overflow:
1052+ case Builtin::BI__builtin_uaddll_overflow:
1053+ case Builtin::BI__builtin_sadd_overflow:
1054+ case Builtin::BI__builtin_saddl_overflow:
1055+ case Builtin::BI__builtin_saddll_overflow:
1056+ arithKind = cir::BinOpOverflowKind::Add;
1057+ break ;
1058+ case Builtin::BI__builtin_usub_overflow:
1059+ case Builtin::BI__builtin_usubl_overflow:
1060+ case Builtin::BI__builtin_usubll_overflow:
1061+ case Builtin::BI__builtin_ssub_overflow:
1062+ case Builtin::BI__builtin_ssubl_overflow:
1063+ case Builtin::BI__builtin_ssubll_overflow:
1064+ arithKind = cir::BinOpOverflowKind::Sub;
1065+ break ;
1066+ case Builtin::BI__builtin_umul_overflow:
1067+ case Builtin::BI__builtin_umull_overflow:
1068+ case Builtin::BI__builtin_umulll_overflow:
1069+ case Builtin::BI__builtin_smul_overflow:
1070+ case Builtin::BI__builtin_smull_overflow:
1071+ case Builtin::BI__builtin_smulll_overflow:
1072+ arithKind = cir::BinOpOverflowKind::Mul;
1073+ break ;
1074+ }
1075+
1076+ clang::QualType resultQTy =
1077+ resultArg->getType ()->castAs <clang::PointerType>()->getPointeeType ();
1078+ auto resultCIRTy = mlir::cast<cir::IntType>(cgm.convertType (resultQTy));
1079+
1080+ mlir::Location loc = getLoc (e->getSourceRange ());
1081+ cir::BinOpOverflowOp arithOp = cir::BinOpOverflowOp::create (
1082+ builder, loc, resultCIRTy, arithKind, x, y);
1083+
1084+ bool isVolatile =
1085+ resultArg->getType ()->getPointeeType ().isVolatileQualified ();
1086+ builder.createStore (loc, emitToMemory (arithOp.getResult (), resultQTy),
1087+ resultPtr, isVolatile);
1088+
1089+ return RValue::get (arithOp.getOverflow ());
1090+ }
1091+
9231092 case Builtin::BIaddressof:
9241093 case Builtin::BI__addressof:
9251094 case Builtin::BI__builtin_addressof:
0 commit comments