Skip to content

Commit

Permalink
Add support for operators on Core.IntLiteral. (#4716)
Browse files Browse the repository at this point in the history
Fixes integer builtins to produce the correct values (and not
CHECK-fail) when used on integer literals. Also adds impls to the
prelude to use the new builtins to perform operations on integer
literals.

Perhaps most importantly, this allows directly initializing `i32` values
with negative numbers, as the negation operation on integer literals now
works.

For testing I've added tests for use of literals with one operator in
each class (addition, multiplication, ordering, bitwise, etc) for which
there are distinct rules or overflow behavior, rather than exhaustively
testing all the combinations. This is aimed at finding a good tradeoff
between maintainability of the tests and thorough test coverage.

Also fixes lowering of heterogeneous shifts and comparisons. These are
currently disabled when one of the operands is an integer literal, but
we may want to allow that when the integer literal operand has a known
constant value.
  • Loading branch information
zygoloid authored Dec 31, 2024
1 parent 624950c commit 4a7aefe
Show file tree
Hide file tree
Showing 59 changed files with 1,838 additions and 419 deletions.
3 changes: 1 addition & 2 deletions core/io.carbon
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,4 @@ fn PrintChar(x: i32) -> i32 = "print.char";
fn ReadChar() -> i32 = "read.char";

// TODO: Change this to a global constant once they are fully supported.
// TODO: Use simply -1 once we support negate on an IntLiteral.
fn EOF() -> i32 { return -(1 as i32); }
fn EOF() -> i32 { return -1; }
29 changes: 29 additions & 0 deletions core/prelude/operators/arithmetic.carbon
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

package Core library "prelude/operators/arithmetic";

import library "prelude/types/int_literal";

// Addition: `a + b`.
interface Add {
fn Op[self: Self](other: Self) -> Self;
Expand Down Expand Up @@ -68,3 +70,30 @@ interface Mod {
interface ModAssign {
fn Op[addr self: Self*](other: Self);
}


// Operations for IntLiteral. These need to be here because IntLiteral has no
// associated library of its own.
impl IntLiteral() as Add {
fn Op[self: Self](other: Self) -> Self = "int.sadd";
}

impl IntLiteral() as Div {
fn Op[self: Self](other: Self) -> Self = "int.sdiv";
}

impl IntLiteral() as Mod {
fn Op[self: Self](other: Self) -> Self = "int.smod";
}

impl IntLiteral() as Mul {
fn Op[self: Self](other: Self) -> Self = "int.smul";
}

impl IntLiteral() as Negate {
fn Op[self: Self]() -> Self = "int.snegate";
}

impl IntLiteral() as Sub {
fn Op[self: Self](other: Self) -> Self = "int.ssub";
}
29 changes: 29 additions & 0 deletions core/prelude/operators/bitwise.carbon
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

package Core library "prelude/operators/bitwise";

import library "prelude/types/int_literal";

// Bit complement: `^a`.
interface BitComplement {
fn Op[self: Self]() -> Self;
Expand Down Expand Up @@ -58,3 +60,30 @@ interface RightShift {
interface RightShiftAssign {
fn Op[addr self: Self*](other: Self);
}


// Operations for IntLiteral. These need to be here because IntLiteral has no
// associated library of its own.
impl IntLiteral() as BitAnd {
fn Op[self: Self](other: Self) -> Self = "int.and";
}

impl IntLiteral() as BitComplement {
fn Op[self: Self]() -> Self = "int.complement";
}

impl IntLiteral() as BitOr {
fn Op[self: Self](other: Self) -> Self = "int.or";
}

impl IntLiteral() as BitXor {
fn Op[self: Self](other: Self) -> Self = "int.xor";
}

impl IntLiteral() as LeftShift {
fn Op[self: Self](other: Self) -> Self = "int.left_shift";
}

impl IntLiteral() as RightShift {
fn Op[self: Self](other: Self) -> Self = "int.right_shift";
}
17 changes: 17 additions & 0 deletions core/prelude/operators/comparison.carbon
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package Core library "prelude/operators/comparison";

export import library "prelude/types/bool";
import library "prelude/types/int_literal";

// Equality comparison: `a == b` and `a != b`.
interface Eq {
Expand All @@ -28,3 +29,19 @@ impl bool as Eq {
fn Equal[self: Self](other: Self) -> bool = "bool.eq";
fn NotEqual[self: Self](other: Self) -> bool = "bool.neq";
}


// Operations for IntLiteral. These need to be here because IntLiteral has no
// associated library of its own.
impl IntLiteral() as Eq {
fn Equal[self: Self](other: Self) -> bool = "int.eq";
fn NotEqual[self: Self](other: Self) -> bool = "int.neq";
}

impl IntLiteral() as Ordered {
// TODO: fn Compare
fn Less[self: Self](other: Self) -> bool = "int.less";
fn LessOrEquivalent[self: Self](other: Self) -> bool = "int.less_eq";
fn Greater[self: Self](other: Self) -> bool = "int.greater";
fn GreaterOrEquivalent[self: Self](other: Self) -> bool = "int.greater_eq";
}
11 changes: 8 additions & 3 deletions toolchain/base/int.h
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,14 @@ constexpr int32_t IntId::InvalidIndex = Invalid.AsIndex();
// an array of `APInt` values and represented as an index in the ID.
class IntStore {
public:
// The maximum supported bit width of an integer type.
// TODO: Pick a maximum size and document it in the design. For now
// we use 2^^23, because that's the largest size that LLVM supports.
static constexpr int MaxIntWidth = 1 << 23;

// Pick a canonical bit width for the provided number of significant bits.
static auto CanonicalBitWidth(int significant_bits) -> int;

// Accepts a signed `int64_t` and uses the mathematical signed integer value
// of it as the added integer value.
//
Expand Down Expand Up @@ -395,9 +403,6 @@ class IntStore {
return IntId::Invalid;
}

// Pick a canonical bit width for the provided number of significant bits.
static auto CanonicalBitWidth(int significant_bits) -> int;

// Canonicalize an incoming signed APInt to the correct bit width.
static auto CanonicalizeSigned(llvm::APInt value) -> llvm::APInt;

Expand Down
Loading

0 comments on commit 4a7aefe

Please sign in to comment.