Instead of including the raw index of the specific, which is unstable
across files and across unrelated changes, use a fingerprint of the
constant values of the specific arguments. This is a placeholder until
we decide on how we want to mangle specific functions.
Add a builtin `"int.convert"` supporting unchecked conversions between
different integer types. This performs a truncation, zero-extension, or
sign-extension, depending on the widths of the operands and the
signedness of the source type. Add explicit `As` support to the prelude.
No implicit conversions are supported yet as we don't have a way to
express the constraint that we can only implicitly convert to wider
types.
Use it in the instruction namer to make instruction names more stable
across unrelated changes to the toolchain or the prelude.
---------
Co-authored-by: Dana Jansens <danakj@orodu.net>
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.
Make `int.snegate` ignore the signedness of its operand and
unconditionally check for signed overflow like all the other `int.s*`
builtins do. Fix the prelude implementation of unary `-` for `Core.UInt`
to use `int.unegate` instead of `int.snegate`.
Fix the test for unsigned negate to actually test negating unsigned
integers, and add some tests that unary `-` also works.
We were mistakenly using the signed builtins, which produce the same
lowering for add/multiply right now, but don't for division and modulus.
When manually flipping SignedOverflowIsUB on, the signed version of add
gains the nsw (no signed wrap) flag, while the unsigned version
(correctly after this change) does not:
```
// CHECK:STDOUT: define i32 @_Cadd_i32.Main(i32 %a, i32 %b) !dbg !4 {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: %int.sadd = add nsw i32 %a, %b, !dbg !7
// CHECK:STDOUT: ret i32 %int.sadd, !dbg !8
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: define i32 @_Cadd_u32.Main(i32 %a, i32 %b) !dbg !9 {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: %int.uadd = add i32 %a, %b, !dbg !10
// CHECK:STDOUT: ret i32 %int.uadd, !dbg !11
// CHECK:STDOUT: }
```
Use a deque to maintain the set of instructions to be walked over. so
that the loop can append more instructions (with their related scope)
during iteration without requiring recursion.
---------
Co-authored-by: jonmeow <jperkins@google.com>
Instead of providing operations only for `i32`, provide them for all
`iN` and `uN` types.
For now, this excludes the `*Assign`, `Inc` and `Dec` interfaces,
because the implementations for those are defined as Carbon functions
rather than builtins, and we can't yet lower definitions for specific
functions, so converting those to be generic breaks the build for our
examples.
We defer lowering initialization with constant values, because the use
of the constant can itself be part of a larger constant that we don't
want to emit. However, when the initialization is for an element of a
non-constant aggregate, we do need to initialize the constant portion.
Non-entry-block allocas will allocate new stack memory each time they're
reached, resulting in leaking stack memory over time for allocas in a
loop. Move all such allocas to the entry block instead, and use an LLVM
intrinsic to mark when the lifetime of the variable actually begins.
In order to support these examples, this adds two new builtins to the
toolchain: `print.char` and `read.char`, which map to the libc functions
`putchar` and `getchar`.
Instead of treating `Core.Int` as the toolchain's builtin `IntType`,
model it as a class that adapts the builtin type. This aligns us better
with the intended language model, gives an associated library for
`impl`s involving `Core.Int` to live within, and opens the door adding
member functions to `Core.Int` if we decide that is desirable.
Remarkably it also seems to make the formatted SemIR a little smaller,
because a call to a generic class generates less IR than a call to a
function.
Such indexing operations are created by array initialization. Since we
switched integer literals to be of type IntLiteral we've been attempting
to index arrays with the (empty) representation of an IntLiteral rather
than with an actual integer value.
This fixes a crash in lowering, at least (though only initializes the
vptr to
null for now) - certainly open to naming feedback on the instruction, or
the
exact semantics (we could have a global vptr instruction that's
referenced from
the existing instructions for reading globals, for instance).
I guess we'll want one type parameter for the vptr_init instruction,
which is
the type that this is a vptr for? (can do that here or in a follow-on
patch)
Actually presenting two options in this one review - if you look at the
specific
commits in this PR, the first commit represents my first attempt - and
if you
look at the overall PR change for the second attempt.
But I'm totally open to completely different approaches/ideas - these
were just
my rough guesses.
Goal is to reduce churn in names in test updates (by churning a lot of
them in this PR).
---------
Co-authored-by: Josh L <josh11b@users.noreply.github.com>
Use it in the remaining few places where we currently hardcode `i32`: as
the index type in array indexing, as the type for literals in `if`
expressions, and as a valid return type for `Run`.
In preparation for changing `Core.Int` to be a class.
---------
Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
We considered a couple of other options for this:
* https://github.com/carbon-language/carbon-lang/pull/4515 Keep the
`ElementIndex` numbering vptr-ignorant, and do +1 offsets as needed -
seems subtle/easy to miss
* https://github.com/carbon-language/carbon-lang/pull/4517 Always have a
zeroth element in the object representation, make it zero-size in the
case of no-vptr - @zygoloid was concerned this would add overhead
especially to stateless objects used in type-trait-like things.
But currently moving forward with this direction - of initializing field
indexes with an invalid value until the end of the class definition,
then assigning field indexes during construction of the class's object
representation struct type. This direction might reinforce/help avoid
premature access to the object representation before the class is
complete, and give a single place where class layout is done (at class
completion) if we want to add more options there, such as class layout
optimizations, etc.
This patch still has problems with object initialization (that #4515
does not have/does address) but does address normal `obj.member` access
correctly.
---------
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
For the few remaining uses of the builtin `i32` type, manually build an
`IntType(Signed, 32)` value instead. These are:
- The return type of `Run`.
- The type that int literals in an `if` expression are converted into.
- The type of an array index expression.
We should consider converting those three cases away from `i32` over
time.
---------
Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
When an `IntLiteral` appears as an operand of an `if` expression,
convert it to `i32` for now, so that we don't reject things like `if
cond then 1 else 2` due to having a non-constant value of type
`IntLiteral`.
For tuple indexing expressions such as `(a, b).0`, convert the index to
type `IntLiteral`, not to type `i32`. This isn't strictly necessary to
do in this PR, but avoids the need to provide an `IntLiteral` -> `i32`
implicit conversion for `no_prelude` tests using this syntax.
Instead, wait until we know whether it is used as a value or reference
expression. This allows us to avoid materializing a temporary if it is
used as a value and the initializing representation holds a copy of a
value representation.
While we don't need a lookup table for an imported impl from a different
library, we do still need to import the name scope so we can compute the
parent scope for mangling purposes.
We previously generated a `value_bind` instruction of the wrong type,
resulting in lowering building bad LLVM IR.
Also fix another issue exposed by this change, where we would import
constants without marking their types as complete, and then crash in
lowering while trying to lower them. This happens in particular for the
`FunctionType`s of functions in `ImplDecl`s. Address this by skipping
lowering for constants with incomplete types.
In this case, the callee may be non-constant because it includes a
reference to `self`, so we need to be able to lower a non-constant
`specific_function`.
Also surround it in square brackets rather than parentheses. This
matches the format used by Clang and GCC, and means diagnostics will
still match the `file:line:col: error: ` pattern used by some IDE tools.
Before:
```console
fail_builtins.carbon:11:11: error(AliasRequiresNameRef): alias initializer must be a name reference
```
After:
```console
fail_builtins.carbon:11:11: error: alias initializer must be a name reference [AliasRequiresNameRef]
```
Also tighten up test regex to only match on `STDERR` lines that list a
file name.
This is to help identify which diagnostics we're actually using.
Note that driver/testdata still has tests which don't pass this flag,
and so continue to test the kind-less (default) behavior.
A small step to virtual functions - adding vtable pointers to the
layout, but not initializing or otherwise using them at this stage.
A few open design questions I'd love feedback on:
* Is this the right/good enough SemIR representation for now? This patch
adds a `is_dynamic` attribute to `SemIR::Class` and populates/flags it
based on the flag of the base class, or if any virtual function is
declared in the class (or, at least that's my intent). Some other
options include:
* Each `Class` could store a `ClassId` (or `TypeId`?) of the (possibly
indirect, possibly self) base class that is the first one that is
dynamic/has a vtable pointer
* Could make the property narrower, like `has vtable pointer` and have
it `true` only on the type that introduces the vtable - then derived
classes would have to walk their base classes to check if they're the
one that needs to define the vtable pointer or not
* Should the vtable be the first element in the type? If there's a
non-dynamic base type, we could have a layout that's `{<non-dynamic base
type>, vtable ptr, <derived members>}`? Derived types would still be
able to uniquely identify where their vtable pointer is just fine... -
and the vtable pointer is, in a sense, a member of that intermediate
type, so it does seem a bit strange to force it to the front - but I
guess it's probably more efficient in some ways?
Open to any other suggestions/advice/thoughts on the direction, etc.
---------
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
Also propagate the pattern IR along with the pattern-match IR, and use
it where appropriate.
Strictly speaking, some parts of the pattern-match IR are allocated
eagerly, while traversing the pattern's parse tree, but they still
aren't actually emitted until we traverse the associated pattern insts.
---------
Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
Generate declarations of specific functions on demand. Definitions are
not emitted yet, and I'm using a temporary, known-broken scheme for name
mangling.
This is a primarily automated change:
- Search & replace for capitalization
-
`(CARBON_DIAGNOSTIC\((?:\n\s+)?\w+,(?:\n\s+)?\s\w+,(?:\n\s+)?\s")([A-Z])`
- `$1\L$2`
- Search & replace for period
-
`(CARBON_DIAGNOSTIC\((?:\n\s+)?\w+,(?:\n\s+)?\s\w+,(?:\n\s+)?\s"(?:[^)]|\n)+)\.("[,)])`
- `$1$2`
- Limited search & replace for `ERROR: ` -> `error: ` in streamed things
- Leaving a TODO for command_line because there's more cleanup that can
be done there
- Modify diagnostic_consumer.cpp
- ERROR -> error
- WARNING -> warning
---------
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
Applies #4278 TEST_NAME substitution to tests. Note I've tried to
structure commits as:
1. Do all the replacements.
2. autoupdate (nothing else) -- this shows incorrect updates.
3. Fix up manually, including autoupdates to get back to original
output.
This seems to be enough to avoid naming collisions for functions in any
of the current test cases (verified by asserting that the name of the
`llvm::Function` matches the name passed to create it - not triggering
LLVM's numbering that happens when names collide)
It currently implements mangling for namespace scopes, class scopes, and
impls.
Nothing generic is mangled yet - haven't looked at how that works,
though evidently it's not covered by existing testing, I guess.
Follow-up change will document the current mangling algorithm in
`toolchain/docs/lower.md`
---------
Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
Co-authored-by: Carbon Infra Bot <carbon-external-infra@google.com>
Mainly, changes the default from -1 to 0 in DiagnosticLoc, still trying
to keep reusing that. Nothing except for the lowered output is affected,
so I think this is fine.
Also, have lowering consistently call GetDiagnosticLoc.
Pulls in one of the CHECKs suggested from #4251
Co-authored-by: David Blaikie <dblaikie@gmail.com>
There's not much mangling happening yet - but Run -> main (and some
overloading numbering happening, maybe LLVM is doing that 'helpfully'
under the hood?) is enough to demonstrate this improvement/fix.
Ah, here it is:
```
#0 llvm::ValueSymbolTable::makeUniqueName (this=0x50287fe5b6c0, V=0x50287fe827e8, UniqueName="F") at external/_main~llvm_project~llvm-project/llvm/lib/IR/ValueSymbolTable.cpp:45
#1 0x000055555c40f964 in llvm::ValueSymbolTable::reinsertValue (this=0x50287fe5b6c0, V=0x50287fe827e8) at external/_main~llvm_project~llvm-project/llvm/lib/IR/ValueSymbolTable.cpp:100
#2 0x000055555c2a91df in llvm::SymbolTableListTraits<llvm::Function>::addNodeToList (this=0x50287fd16f18, V=0x50287fe827e8) at external/_main~llvm_project~llvm-project/llvm/lib/IR/SymbolTableListTraitsImpl.h:75
#3 0x000055555c2a90e5 in llvm::iplist_impl<llvm::simple_ilist<llvm::Function>, llvm::SymbolTableListTraits<llvm::Function> >::insert (this=0x50287fd16f18, where=..., New=0x50287fe827e8)
at external/_main~llvm_project~llvm-project/llvm/include/llvm/ADT/ilist.h:166
#4 0x000055555c27fef2 in llvm::iplist_impl<llvm::simple_ilist<llvm::Function>, llvm::SymbolTableListTraits<llvm::Function> >::push_back (this=0x50287fd16f18, val=0x50287fe827e8) at external/_main~llvm_project~llvm-project/llvm/include/llvm/ADT/ilist.h:250
#5 0x000055555c27faeb in llvm::Function::Function (this=0x50287fe827e8, Ty=0x50287fd43058, Linkage=llvm::GlobalValue::ExternalLinkage, AddrSpace=0, name="F", ParentModule=0x50287fd16f00) at external/_main~llvm_project~llvm-project/llvm/lib/IR/Function.cpp:521
#6 0x0000555559441f95 in llvm::Function::Create (Ty=0x50287fd43058, Linkage=llvm::GlobalValue::ExternalLinkage, AddrSpace=0, N="F", M=0x50287fd16f00) at external/_main~llvm_project~llvm-project/llvm/include/llvm/IR/Function.h:175
#7 0x000055555c27ebac in llvm::Function::Create (Ty=0x50287fd43058, Linkage=llvm::GlobalValue::ExternalLinkage, N="F", M=...) at external/_main~llvm_project~llvm-project/llvm/lib/IR/Function.cpp:398
#8 0x0000555558ce7bb5 in Carbon::Lower::FileContext::BuildFunctionDecl (this=0x7fffffffc438, function_id=...) at toolchain/lower/file_context.cpp:257
```
That's where LLVM decides to make a new name (name.number) when asked to
create a new global with the same name as an existing global.
It's not a valid mangling scheme - since the name won't be stable
between different compilations, but it is enough to make
single-compilation code build/run for now.
The source line debug info generation assumed that the function would
have debug info. Check for a non-null di_subprogram_ to ensure we are
emitting debug info for the function.
Rather than checking the di_builder_ - this way if we implement
`nodebug` function attributes, it'll fall out naturally (by creating a
null di_subprogram_) rather than having to come back and change this
from "is debug info enabled" to "is debug info enabled for this
function" later on.