Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Types from beginning to end #37

Merged
merged 98 commits into from
Feb 7, 2023
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
98 commits
Select commit Hold shift + click to select a range
0d41365
Initial Mess
LensPlaysGames Jan 21, 2023
fe4610d
Make it work more betterer
LensPlaysGames Jan 22, 2023
2f4d462
[Bugfix] Zero extending loads fixes *a lot*
LensPlaysGames Jan 22, 2023
9a013f3
[Bug] Identify bug with binary operator type
LensPlaysGames Jan 22, 2023
5831094
[Bugfix] Fix error in format string
LensPlaysGames Jan 23, 2023
055931c
[Codegen] Handle size of type when calculating address offset
LensPlaysGames Jan 27, 2023
08f8d36
[Codegen] Make IR_LOAD great again (arrays! (again))
LensPlaysGames Jan 27, 2023
2578acc
[x86_64/Bugfix] Missing register size parameter in femit
LensPlaysGames Jan 27, 2023
89337ae
[MSWIN/Bugfix] Handle error of `SymFromAddr()`
LensPlaysGames Jan 27, 2023
9fa9485
[Sema] Handle some basic type casting cases in typechecker
LensPlaysGames Jan 27, 2023
3457d53
[Typo] Forgetting a newline is bad, mmkay?
LensPlaysGames Jan 27, 2023
b5b3183
[Minor] Fix horribly phrased comment
LensPlaysGames Jan 29, 2023
8a94037
[Docs] Better comments regarding type helpers in `ast.h`
LensPlaysGames Jan 29, 2023
61f28a8
[Minor] Add signedness reminder to casting codegen todo
LensPlaysGames Jan 29, 2023
98ae71e
[Bugfix] Copy and paste strikes again :I
LensPlaysGames Jan 29, 2023
f06972a
[Codegen] Handle subscript operator all at once, instead of split
LensPlaysGames Jan 29, 2023
aa23eae
[Minor] Add commentary on array pointer decay codegen
LensPlaysGames Jan 29, 2023
c9be95c
[Minor] Remove unnecessary `t_void` assignments from IR helpers
LensPlaysGames Jan 29, 2023
61d343d
[Bugfix] IR type of bitwise not was incorrectly always `t_integer`
LensPlaysGames Jan 29, 2023
1ad6dbf
[Codegen/x86_64] Remove useless `r128` RegSize
LensPlaysGames Jan 29, 2023
d82cd3d
[Codegen/x86_64] Don't emit xor + mov when a 32-bit mov is usable
LensPlaysGames Jan 29, 2023
9b30942
[Codegen/IR] Make variable allocation instructions pointers to type
LensPlaysGames Jan 29, 2023
20e42a0
[Sema/Minor] Some updates to typecasting
LensPlaysGames Jan 29, 2023
3ad2392
[TODO] `as void` discard cast
LensPlaysGames Jan 29, 2023
e7d77a7
[Tests] Lines with trailing whitespace keep me up at night
LensPlaysGames Jan 29, 2023
b4af7c9
[Codegen/x86_64] Update incorrect comments regarding var. args
LensPlaysGames Jan 30, 2023
8013c43
[Codegen/x86_64] Mention `movzx` instruction where applicable
LensPlaysGames Jan 30, 2023
a836f0b
[Codegen/x86_64] Add `t_pointer` primitive type
LensPlaysGames Jan 30, 2023
9d23bd2
[Sema] Fix `t_pointer` definition
LensPlaysGames Jan 30, 2023
55e1ec0
[Sema] Disallow typecasting between arrays
LensPlaysGames Jan 31, 2023
e339100
[Minor] TODO comment in Sema
LensPlaysGames Jan 31, 2023
6c4570d
[Examples] Using a byte array as a C string
LensPlaysGames Jan 31, 2023
a94f836
[Bugfix] Lexer no longer relies on null terminator
LensPlaysGames Feb 1, 2023
933ed59
[Frontend] Basic string literal support :O
LensPlaysGames Feb 1, 2023
312d4e7
[Codegen] Very basic codegen of string literals
LensPlaysGames Feb 1, 2023
ac386a8
[Examples] Basic string literal example
LensPlaysGames Feb 1, 2023
ab4eac2
[TODO] Arrays have two kinds of loading we need to be able to emit
LensPlaysGames Feb 1, 2023
4423fee
[AST] Make `ast_print_node` publicly available
LensPlaysGames Feb 2, 2023
c57b388
[Minor] Formatting
LensPlaysGames Feb 2, 2023
ab7dcf8
[Sema] Emit error over previous todo as we now handle (some) casting
LensPlaysGames Feb 2, 2023
db2d432
[Sema] Disallow non-equal incomplete types entirely
LensPlaysGames Feb 2, 2023
1bd10b3
[Minor/AST] Add meaningful docstring to `type_is_incomplete_canon`
LensPlaysGames Feb 2, 2023
66f7289
[Minor/AST] Better formatting of docstring for `type_canonical`
LensPlaysGames Feb 2, 2023
b125c17
[Minor/TODO] Update unnecessarily narrowing statement :P
LensPlaysGames Feb 2, 2023
bee8136
[AST] Remove `id` system entirely
LensPlaysGames Feb 2, 2023
afebae2
[Tests] Two tests---one passes, one fails
LensPlaysGames Feb 2, 2023
e669db3
[Codegen/IR] Remove `cached_*` members from `IRStaticVariable`
LensPlaysGames Feb 2, 2023
c9ccbb2
[Minor/AST] Stub implementation of `type_alignof`
LensPlaysGames Feb 2, 2023
6615957
[Codegen/x86_64] Use `type_sizeof(t_pointer)` where applicable
LensPlaysGames Feb 2, 2023
9b71982
[Codegen/IR] Fix overwrite of `rhs` of subscript operator
LensPlaysGames Feb 2, 2023
dc49514
[Minor/Codegen] Update diagnostic message
LensPlaysGames Feb 2, 2023
4e3e0f8
[Tests] Add `negative-numbers.un`
LensPlaysGames Feb 2, 2023
ec7b772
[Minor] Be slightly more explicit about primitive type defined name
LensPlaysGames Feb 2, 2023
974bdff
[Minor/Codegen] Fix scuffed diagnostic message
LensPlaysGames Feb 2, 2023
32f6a44
[IR] Create `ir_static_reference()` to reference an existing static
LensPlaysGames Feb 3, 2023
b2d090d
[Codegen] Use `ir_static_reference()` to create many references
LensPlaysGames Feb 3, 2023
b14fa1c
[Bugfix/x86_64] Add missing parameter...
LensPlaysGames Feb 3, 2023
8281a44
[Minor/Codegen] Add TODO comment
LensPlaysGames Feb 3, 2023
ec35e50
[Codegen/x86_64] Begin move away from `va_list` towards typed params
LensPlaysGames Feb 3, 2023
6574a1d
[Codegen/x86_64] Move further away from variable args...
LensPlaysGames Feb 3, 2023
e830a9f
[Codegen/x86_64] Moving even further away from variable args...
LensPlaysGames Feb 3, 2023
339e07c
[Codegen/x86_64] `femit_name_to_reg()` typed parameters
LensPlaysGames Feb 3, 2023
84f1e10
[Codegen/x86_64] `femit_reg_to_mem()` typed parameters
LensPlaysGames Feb 3, 2023
80749cf
[Codegen/x86_64] Nearly completely moved away from variable args...
LensPlaysGames Feb 3, 2023
81aaf8e
[Codegen/x86_64] More comprehensive ICE error message in `femit()`
LensPlaysGames Feb 3, 2023
a400f57
[Minor/x86_64] Comments, error message
LensPlaysGames Feb 3, 2023
4a70c4c
Merge branch 'main' into ir_types_bb
LensPlaysGames Feb 3, 2023
cd2381a
[Minor/Codegen] Outline places where string literals need handled
LensPlaysGames Feb 3, 2023
f922e21
[Minor/Codegen] Yet still always more to do due soon
LensPlaysGames Feb 3, 2023
13b8210
[Bugfix] Add missing zero initialiser (needed by MSVC)
LensPlaysGames Feb 4, 2023
33c195c
[Minor] Remove accidentally tracked file
LensPlaysGames Feb 4, 2023
49c9970
[Sema] Fix copy-and-paste error
LensPlaysGames Feb 6, 2023
e594ee5
[UX] Allow `colors` as well as `colours` in CLI
LensPlaysGames Feb 7, 2023
b95d879
[TODO] String literals are parsed, now
LensPlaysGames Feb 7, 2023
b7be438
Disable IR intake as it is severely lacking in development right now
LensPlaysGames Feb 7, 2023
49f6762
[Bugfix] Fix types in wrong order in error message
LensPlaysGames Feb 7, 2023
6c49cac
[Sema] Move some `type_is_*` functions up to `ast.h` from `typechecke…
LensPlaysGames Feb 7, 2023
7253339
[Minor/Sema] Use `vector_back` instead of manual calculation
LensPlaysGames Feb 7, 2023
7b84f66
[Minor/Sema] Actually use `vector_back_or` in case of no children
LensPlaysGames Feb 7, 2023
771b9b4
[Minor/Sema] This should now work pretty much as expected
LensPlaysGames Feb 7, 2023
df8ffb0
[Minor/Sema] Very minor formatting
LensPlaysGames Feb 7, 2023
5a60f48
[Bugfix] Source spans of assignments were off; this fixes them
LensPlaysGames Feb 7, 2023
cc09b8b
[Sema] Use `type_is_*` instead of direct comparisons
LensPlaysGames Feb 7, 2023
836f99b
[Codegen] Improve codegen of subscript variable reference
LensPlaysGames Feb 7, 2023
acd725c
[AST] Update `ast_print_node` with easier to use signature
LensPlaysGames Feb 7, 2023
f3fab2d
[Codegen] Remove now-unnecessary array bodge in var. ref. codegen
LensPlaysGames Feb 7, 2023
a8241fa
[Codegen] ¡Subscript of local variable!
LensPlaysGames Feb 7, 2023
6c027c7
[Codegen] Apparently better ¡Codegen of Subscript of local variable!
LensPlaysGames Feb 7, 2023
c7f87aa
[Codegen/x86_64] Fix clobber values of `does_clobber` for shift instr…
LensPlaysGames Feb 7, 2023
88715b4
[Tests] Add bit-shifting left and right tests
LensPlaysGames Feb 7, 2023
1104d93
[AST] Rename `t_pointer` to `t_void_ptr`
LensPlaysGames Feb 7, 2023
b222c7f
[Codegen/IR] Remove use of `ir_static_reference`
LensPlaysGames Feb 7, 2023
6411d36
[Minor/IR] Simplify wording of comment
LensPlaysGames Feb 7, 2023
40b4430
[Minor/Codegen] Comments; fixed a typo
LensPlaysGames Feb 7, 2023
f1f876c
[Codegen] Rename `var` to the more correct `var_decl`
LensPlaysGames Feb 7, 2023
8282edc
[Sema] Get rid of `is_*` wrappers, where possible
LensPlaysGames Feb 7, 2023
3a9c115
[Codegen/IR] Fix assigned type of `IR_LOAD` instructions
LensPlaysGames Feb 7, 2023
79c22b1
[TODO] NODISCARD should be default for non-void return types
LensPlaysGames Feb 7, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
- [ ] Function bodies must be blocks or preceded by `=`.
- [ ] `ext` functions may have a body.
- [ ] Implicit cast sema pass: `a + b` where `a` is a `byte` and `b` an `integer` -> `(a as integer) + b`
- [ ] Optimisation
- [ ] Zero subscript still does add/multiply when it doesn't need to
- [ ] Eliminate unused parameters (they are currently allocated registers)
- [ ] Attributes
- [ ] Parsing
- [ ] `[[noreturn]]`
Expand All @@ -36,12 +39,14 @@
- [ ] Disallow overloading on the return value.
- [ ] Proper checking for incomplete types in the parser.
- [ ] Types in the IR
- [ ] Byte type
- [ ] Type info in codegen/IR.
- [x] Byte type
- [x] Type info in codegen/IR.
- [ ] Backend: Handle size/alignment requirements
- [ ] Use eax, ax, al, etc.
- [x] Use eax, ax, al, etc.
- [ ] Actually implementing casts.
- [ ] During codegen, we should actually output `zext`/`sext` if needed. Otherwise truncation is automatic.
- [ ] Update IR parser
- [ ] Binary operators need to pick return type instead of strictly returning `integer`
LensPlaysGames marked this conversation as resolved.
Show resolved Hide resolved
- [ ] Arrays
- [ ] Semantic analysis for static arrays.
- [ ] Codegen
Expand Down
4 changes: 4 additions & 0 deletions examples/byte.un
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
a : byte = 34
b : byte = 35
c : byte = a + b
c
8 changes: 6 additions & 2 deletions src/ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -514,9 +514,11 @@ Type *ast_make_type_function(
/// ===========================================================================
/// Get a string representation of a type.
/// \return The string representation of the type. The string is allocated
/// as if with `malloc` and must be freed by the caller.
/// with malloc() and must be freed by the caller.
string typename(Type *type, bool colour);

// FIXME: I don't know what canonical means, and this docstring doesn't
// help me :P
/// Get the canonical type of a type.
/// \return NULL if the type is incomplete.
Type *type_canonical(Type *type);
LensPlaysGames marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -526,13 +528,15 @@ Type *type_canonical(Type *type);
/// This function strips nested named types until there is only one left.
Type *type_last_alias(Type *type);

// FIXME: What makes a type complete vs incomplete, in the eyes of this
// function?
/// Check if a type is incomplete.
bool type_is_incomplete(Type *type);
LensPlaysGames marked this conversation as resolved.
Show resolved Hide resolved

/// Check if a canonical type is incomplete.
bool type_is_incomplete_canon(Type *type);
LensPlaysGames marked this conversation as resolved.
Show resolved Hide resolved

/// Get the size of a type.
/// Get the size of a type, in bytes.
LensPlaysGames marked this conversation as resolved.
Show resolved Hide resolved
usz type_sizeof(Type *type);

/// Check if a type is void.
Expand Down
52 changes: 40 additions & 12 deletions src/codegen.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include <codegen.h>

#include <ast.h>
#include <codegen/codegen_forward.h>
#include <codegen/intermediate_representation.h>
#include <codegen/x86_64/arch_x86_64.h>
Expand Down Expand Up @@ -153,7 +154,7 @@ static void codegen_expr(CodegenContext *ctx, Node *expr) {
case NODE_DECLARATION:
expr->ir = expr->declaration.static_
? ir_create_static(ctx, expr->type, as_span(expr->declaration.name))
: ir_stack_allocate(ctx, type_sizeof(expr->type));
: ir_stack_allocate(ctx, expr->type);

/// Emit the initialiser if there is one.
if (expr->declaration.init) {
Expand Down Expand Up @@ -215,7 +216,7 @@ static void codegen_expr(CodegenContext *ctx, Node *expr) {

/// Insert a phi node for the result of the if in the join block.
if (!type_is_void(expr->type)) {
IRInstruction *phi = ir_phi(ctx);
IRInstruction *phi = ir_phi(ctx, expr->type);
ir_phi_argument(phi, last_then_block, expr->if_.then->ir);
ir_phi_argument(phi, last_else_block, expr->if_.else_->ir);
expr->ir = phi;
Expand Down Expand Up @@ -318,11 +319,20 @@ static void codegen_expr(CodegenContext *ctx, Node *expr) {
}

/// Typecast.
case NODE_CAST: { TODO(); }
case NODE_CAST: {
Type *t_to = expr->type;
Type *t_from = expr->cast.value->type;

usz to_sz = type_sizeof(t_to);
usz from_sz = type_sizeof(t_from);

TODO("Codegen cast from %T to %T", t_from, t_to);
LensPlaysGames marked this conversation as resolved.
Show resolved Hide resolved
}

/// Binary expression.
case NODE_BINARY: {
Node * const lhs = expr->binary.lhs, * const rhs = expr->binary.rhs;
Node *const lhs = expr->binary.lhs;
Node *const rhs = expr->binary.rhs;

/// Assignment needs to be handled separately.
if (expr->binary.op == TK_COLON_EQ) {
Expand Down Expand Up @@ -350,9 +360,24 @@ static void codegen_expr(CodegenContext *ctx, Node *expr) {
return;
}

// TODO: Just use lhs operand of subscript operator when right hand
// side is a compile-time-known zero value.

/// Emit the operands.
codegen_expr(ctx, lhs);
codegen_expr(ctx, rhs);
if (expr->binary.op == TK_LBRACK) {
LensPlaysGames marked this conversation as resolved.
Show resolved Hide resolved
// An array subscript needs multiplied by the sizeof the array's base type.
if (lhs->type->kind == TYPE_ARRAY) {
IRInstruction *immediate = ir_immediate(ctx, t_integer, type_sizeof(lhs->type->array.of));
rhs->ir = ir_mul(ctx, rhs->ir, immediate);
LensPlaysGames marked this conversation as resolved.
Show resolved Hide resolved
}
// A pointer subscript needs multiplied by the sizeof the pointer's base type.
else if (lhs->type->kind == TYPE_ARRAY) {
LensPlaysGames marked this conversation as resolved.
Show resolved Hide resolved
IRInstruction *immediate = ir_immediate(ctx, t_integer, type_sizeof(lhs->type->pointer.to));
rhs->ir = ir_mul(ctx, rhs->ir, immediate);
LensPlaysGames marked this conversation as resolved.
Show resolved Hide resolved
}
}

/// Emit the binary instruction.
switch (expr->binary.op) {
Expand Down Expand Up @@ -400,9 +425,9 @@ static void codegen_expr(CodegenContext *ctx, Node *expr) {
case TK_AT:
/// TODO: This check for a function pointer is a bit sus. We shouldn’t
/// even get here if this is actually a function pointer...
if (expr->unary.value->type->pointer.to->kind == TYPE_FUNCTION) {
if (expr->unary.value->type->pointer.to->kind == TYPE_FUNCTION)
expr->ir = expr->unary.value->ir;
} else {
else {
expr->ir = ir_load(ctx, expr->unary.value->ir);
}
return;
Expand All @@ -423,12 +448,17 @@ static void codegen_expr(CodegenContext *ctx, Node *expr) {
/// Literal expression. Only integer literals are supported for now.
case NODE_LITERAL:
if (expr->literal.type != TK_NUMBER) DIAG(DIAG_SORRY, expr->source_location, "Emitting non-integer literals not supported");
expr->ir = ir_immediate(ctx, expr->literal.integer);
// TODO: SEMA should probably have already lowered integer_literal type, so we *should* have a type already available on the literal node...
expr->ir = ir_immediate(ctx, expr->type, expr->literal.integer);
return;

/// Variable reference.
case NODE_VARIABLE_REFERENCE:
expr->ir = ir_load(ctx, expr->var->val.node->ir);
// TODO: Be smarter about when an array should decay to a pointer or not.
// Maybe it never should, and this should be implemented per backend?
LensPlaysGames marked this conversation as resolved.
Show resolved Hide resolved
if (expr->ir->type->kind == TYPE_ARRAY)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To expound on this: If we get here, we should assume that we have a case like e.g. a := b where b is an array type, and we’re trying to emit b, in which case we just emit a load and be done w/ it.

If we’re dealing w/ something like b[0] instead (or a in a := b, or &b), then we should check for that case when codegenning the subscript operator (or the assignment or addressof operator) and not even try and emit b in the first place iff it is an array. This is also how cases like @foo := bar are handled because dereferencing suffers from all the same problems...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not even try and emit b in the first place iff it is an array

This works fine in simple cases (e.g. &b), b has to be an lvalue anyway for us to be able to take its address, and we don’t need to emit a load to it to know its address.

Where this probably doesn’t work atm is if we have something like (if cond { a } else { b }) := c, but then again, I’m not sure this case would work currently, even if a and b are regular variables... so perhaps we might have to change it to where it only actually loads the value once we know that is used by some other instruction (and used AS A VALUE, not as an address to e.g. store to). I’m not sure though if this should happen by somehow not generating a load when we only want the lvalue or by removing the load afterwards if it’s clear that it’s unused.

Optimisations would take care of the latter anyway, so perhaps a solution would be to make optimising dead loads mandatory? Only trivially dead loads, i.e. loads that have no users at all, that is. We wouldn’t have to account for loads that are indirectly dead because, although they are used to compute some value, that value is also dead code. That doesn’t matter in this case since if we were to emit a load when we actually just need an lvalue, then the load proper would be completely unused.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The top-down approach (i.e. checking if a value needs to be loaded or if we just want its address) would entail emitting potentially arbitrarily complex and nested expressions while not actually loading anything and instead just collecting the lvalues. All of this is just an idea tho; I haven’t thought too much about this in a while and it also feels like I’m overcomplicating things here candidly...

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Honestly, I feel really dumb when I think about this problem. It seems so simple, but it's really hard, lmao. One thing I am confused about is how do I actually emit a load of a pointer (i.e. the pointer) without dereferencing it?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This entire thing is basically more or less related to getting something like this to work properly:

image

I guess there is a finite number of expressions that may return an lvalue (e.g. if expressions may, but while loops can’t), so one option would be to leave codegen_expr untouched and add a separate codegen_lvalue or sth that gets called e.g. when emitting an assignment or array subscript, and instead of loading the value, it just ‘loads’ the address. For example, the value of the if expression in (if a { @b ⟩ else { @c }) := 5 at runtime would be the address of b or c, to which we could then emit an (indirect) store. This entire thing is basically just about handling lvalues properly. Once we can codegen e.g. that if expression, then arrays should just work because they’re basically the same thing...

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm beginning to understand somewhat now; a major point of confusion was the phrasing "not emit a load" or similar (I'll be the first to admit that is on me). I was confused as to where the value would come from if it's never loaded. But it seems like what you are referencing is the fact that the "load" has already been emitted, and therefore it's not necessary to emit it again. Instead, we don't emit a load because one already exists; we can just use that instructions value. What helped me see this was you pointing out the current handling of dereference, as I know how that works and why it's needed.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can

    %b = alloca 8
    %c = alloca 8
    ;; ...
    br.cond %a, bb_b, bb_c
bb_b:
    br bb_end
bb_c:
    br bb_end
bb_end:
    %if = phi [bb_b: %b, bb_c: %c]
    store into %if, 5

be turned into

    br.cond %a, bb_b, bb_c
bb_b:
    %b = alloca 8
    br bb_end
bb_c:
    %c = alloca 8
    br bb_end
bb_end:
    %if = phi [bb_b: %b, bb_c: %c]
    store into %if, 5

Not saying it should, really just wondering if they are equivalent

Copy link
Contributor

@Sirraide Sirraide Feb 2, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They’re not really the same. The latter is what you’d get if you did this:

(if a { b : integer } else { c : integer }) := 5

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An alloca is a variable declaration

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The codegen for the if is everything after and including the br.cond. It’s assumed that b and c are defined earlier on in the function; I included the allocas mostly to make clear that these are supposed to be variables

expr->ir->type = ast_make_type_pointer(ctx->ast, expr->type->source_location, expr->type->array.of);
return;

/// Function reference. These should have all been removed by the semantic analyser.
Expand Down Expand Up @@ -456,13 +486,11 @@ void codegen_function(CodegenContext *ctx, Node *node) {
/// Emit the function body.
codegen_expr(ctx, node->function.body);

/// If the we can return from here, and this function doesn’t return void,
/// If we can return from here, and this function doesn’t return void,
/// then return the return value; otherwise, just return nothing.
if (!ir_is_closed(ctx->block) && !type_is_void(node->type->function.return_type)) {
if (!ir_is_closed(ctx->block) && !type_is_void(node->type->function.return_type))
ir_return(ctx, node->function.body->ir);
} else {
ir_return(ctx, NULL);
}
else ir_return(ctx, NULL);
}

/// ===========================================================================
Expand Down
Loading