Add builtins for compound assignment operators. (#5335)

Provide builtins for compound assignments instead of defining them in
the prelude as a use of a binary operator and an assignment. This allows
us to lower compound assignment directly to LLVM operations instead of
producing a function call. In the short term this also allows us to
define a type-generic compound assignment in the prelude.
This commit is contained in:
Richard Smith
2025-04-21 20:38:11 +00:00
committed by GitHub
parent 2bdea71c25
commit b5ae988a08
39 changed files with 1373 additions and 312 deletions
+97 -1
View File
@@ -34,6 +34,9 @@ struct ValidateState {
TypeId type_params[MaxTypeParams] = {TypeId::None, TypeId::None};
};
template <typename TypeConstraint>
auto Check(const File& sem_ir, ValidateState& state, TypeId type_id) -> bool;
// Constraint that a type is generic type parameter `I` of the builtin,
// satisfying `TypeConstraint`. See ValidateSignature for details.
template <int I, typename TypeConstraint>
@@ -63,6 +66,20 @@ struct BuiltinType {
}
};
// Constraint that a type is a pointer to another type. See ValidateSignature
// for details.
template <typename PointeeT>
struct PointerTo {
static auto Check(const File& sem_ir, ValidateState& state, TypeId type_id)
-> bool {
if (!sem_ir.types().Is<SemIR::PointerType>(type_id)) {
return false;
}
return SemIR::Check<PointeeT>(sem_ir, state,
sem_ir.GetPointeeType(type_id));
}
};
// Constraint that a type is `()`, used as the return type of builtin functions
// with no return value.
struct NoReturn {
@@ -219,6 +236,10 @@ using IntU = TypeParam<1, AnyInt>;
// generic type parameter that is constrained to be a sized integer type.
using SizedIntT = TypeParam<0, AnySizedInt>;
// Convenience name used in the builtin type signatures below for a second
// generic type parameter that is constrained to be a sized integer type.
using SizedIntU = TypeParam<1, AnySizedInt>;
// Convenience name used in the builtin type signatures below for a first
// generic type parameter that is constrained to be an float type.
using FloatT = TypeParam<0, AnyFloat>;
@@ -337,10 +358,85 @@ constexpr BuiltinInfo IntXor = {"int.xor",
constexpr BuiltinInfo IntLeftShift = {
"int.left_shift", ValidateSignature<auto(IntT, IntU)->IntT>};
// "int.left_shift": integer right shift.
// "int.right_shift": integer right shift.
constexpr BuiltinInfo IntRightShift = {
"int.right_shift", ValidateSignature<auto(IntT, IntU)->IntT>};
// "int.sadd_assign": integer in-place addition.
constexpr BuiltinInfo IntSAddAssign = {
"int.sadd_assign",
ValidateSignature<auto(PointerTo<SizedIntT>, SizedIntT)->NoReturn>};
// "int.ssub_assign": integer in-place subtraction.
constexpr BuiltinInfo IntSSubAssign = {
"int.ssub_assign",
ValidateSignature<auto(PointerTo<SizedIntT>, SizedIntT)->NoReturn>};
// "int.smul_assign": integer in-place multiplication.
constexpr BuiltinInfo IntSMulAssign = {
"int.smul_assign",
ValidateSignature<auto(PointerTo<SizedIntT>, SizedIntT)->NoReturn>};
// "int.sdiv_assign": integer in-place division.
constexpr BuiltinInfo IntSDivAssign = {
"int.sdiv_assign",
ValidateSignature<auto(PointerTo<SizedIntT>, SizedIntT)->NoReturn>};
// "int.smod_assign": integer in-place modulo.
constexpr BuiltinInfo IntSModAssign = {
"int.smod_assign",
ValidateSignature<auto(PointerTo<SizedIntT>, SizedIntT)->NoReturn>};
// "int.uadd_assign": unsigned integer in-place addition.
constexpr BuiltinInfo IntUAddAssign = {
"int.uadd_assign",
ValidateSignature<auto(PointerTo<SizedIntT>, SizedIntT)->NoReturn>};
// "int.usub_assign": unsigned integer in-place subtraction.
constexpr BuiltinInfo IntUSubAssign = {
"int.usub_assign",
ValidateSignature<auto(PointerTo<SizedIntT>, SizedIntT)->NoReturn>};
// "int.umul_assign": unsigned integer in-place multiplication.
constexpr BuiltinInfo IntUMulAssign = {
"int.umul_assign",
ValidateSignature<auto(PointerTo<SizedIntT>, SizedIntT)->NoReturn>};
// "int.udiv_assign": unsigned integer in-place division.
constexpr BuiltinInfo IntUDivAssign = {
"int.udiv_assign",
ValidateSignature<auto(PointerTo<SizedIntT>, SizedIntT)->NoReturn>};
// "int.mod_assign": integer in-place modulo.
constexpr BuiltinInfo IntUModAssign = {
"int.umod_assign",
ValidateSignature<auto(PointerTo<SizedIntT>, SizedIntT)->NoReturn>};
// "int.and_assign": integer in-place bitwise and.
constexpr BuiltinInfo IntAndAssign = {
"int.and_assign",
ValidateSignature<auto(PointerTo<SizedIntT>, SizedIntT)->NoReturn>};
// "int.or_assign": integer in-place bitwise or.
constexpr BuiltinInfo IntOrAssign = {
"int.or_assign",
ValidateSignature<auto(PointerTo<SizedIntT>, SizedIntT)->NoReturn>};
// "int.xor_assign": integer in-place bitwise xor.
constexpr BuiltinInfo IntXorAssign = {
"int.xor_assign",
ValidateSignature<auto(PointerTo<SizedIntT>, SizedIntT)->NoReturn>};
// "int.left_shift_assign": integer in-place left shift.
constexpr BuiltinInfo IntLeftShiftAssign = {
"int.left_shift_assign",
ValidateSignature<auto(PointerTo<SizedIntT>, SizedIntU)->NoReturn>};
// "int.right_shift_assign": integer in-place right shift.
constexpr BuiltinInfo IntRightShiftAssign = {
"int.right_shift_assign",
ValidateSignature<auto(PointerTo<SizedIntT>, SizedIntU)->NoReturn>};
// "int.eq": integer equality comparison.
constexpr BuiltinInfo IntEq = {"int.eq",
ValidateSignature<auto(IntT, IntU)->Bool>};