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 23 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
2 changes: 1 addition & 1 deletion TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
- [ ] Length operator: `#`
- [ ] Subscripting
- [ ] Strings
- [ ] Parsing string literals.
- [x] Parsing string literals.
- [ ] Codegen.
- [ ] Backend.
- [ ] Structs
Expand Down
24 changes: 20 additions & 4 deletions src/ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ static Type t_byte_def = {
};

Type * const t_void = &t_void_def;
Type * const t_pointer = &t_void_pointer_def;
Type * const t_void_ptr = &t_void_pointer_def;
Type * const t_integer_literal = &t_integer_literal_def;
Type * const t_integer = &t_integer_def;
Type * const t_byte = &t_byte_def;
Expand Down Expand Up @@ -511,6 +511,16 @@ bool type_is_void(Type *type) {
return type_canonical(type) == t_void;
}

bool type_is_pointer(Type *type) {
Type * t = type_canonical(type);
return t && t->kind == TYPE_POINTER;
}

bool type_is_array(Type *type) {
Type * t = type_canonical(type);
return t && t->kind == TYPE_ARRAY;
}

/// ===========================================================================
/// Miscellaneous AST functions.
/// ===========================================================================
Expand Down Expand Up @@ -607,7 +617,7 @@ static void ast_print_children(
);

/// Print a node.
void ast_print_node(
void ast_print_node_internal(
FILE *file,
const Node *logical_parent,
const Node *node,
Expand Down Expand Up @@ -755,6 +765,12 @@ void ast_print_node(
}
}

void ast_print_node(const Node *node) {
string_buffer buf = {0};
ast_print_node_internal(stdout, NULL, node, &buf);
vector_delete(buf);
}

/// Scope tree for printing scopes.
typedef struct scope_tree_node {
const Scope *scope;
Expand Down Expand Up @@ -836,7 +852,7 @@ void ast_print(FILE *file, const AST *ast) {
string_buffer buf = {0};

/// Print the root node.
ast_print_node(file, NULL, ast->root, &buf);
ast_print_node_internal(file, NULL, ast->root, &buf);
}

/// Print the children of a node.
Expand All @@ -861,7 +877,7 @@ static void ast_print_children(
format_to(buf, "%s", node == vector_back(*nodes) ? " " : "│ ");

/// Print the node.
ast_print_node(file, logical_parent, node, buf);
ast_print_node_internal(file, logical_parent, node, buf);

/// Restore the leading text.
buf->size = sz;
Expand Down
14 changes: 9 additions & 5 deletions src/ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,13 @@ usz type_alignof(Type *type);
/// Check if a type is void.
bool type_is_void(Type *type);

/// Check if a type is of pointer type.
bool type_is_pointer(Type *type);

/// Check if a type is of array type.
bool type_is_array(Type *type);


/// ===========================================================================
/// Miscellaneous AST functions.
/// ===========================================================================
Expand All @@ -588,10 +595,7 @@ void ast_print(FILE *file, const AST *ast);
void ast_print_scope_tree(FILE *file, const AST *ast);

/// Print a node and all of it's children.
/// Use like so:
/// string_buffer buf = {0};
/// ast_print_node(file, NULL, node, &buf);
void ast_print_node(FILE *file, const Node *logical_parent, const Node *node, string_buffer *leading_text);
void ast_print_node(const Node *node);

/// Intern a string.
size_t ast_intern_string(AST *ast, span string);
Expand All @@ -603,7 +607,7 @@ void ast_replace_node(AST *ast, Node *old, Node *new);
/// Builtin types.
/// ===========================================================================
extern Type *const t_void;
extern Type *const t_pointer;
extern Type *const t_void_ptr;
extern Type *const t_integer_literal;
extern Type *const t_integer;
extern Type *const t_byte;
Expand Down
33 changes: 16 additions & 17 deletions src/codegen.c
Original file line number Diff line number Diff line change
Expand Up @@ -361,31 +361,36 @@ static void codegen_expr(CodegenContext *ctx, Node *expr) {
}

if (expr->binary.op == TK_LBRACK) {
LensPlaysGames marked this conversation as resolved.
Show resolved Hide resolved
codegen_expr(ctx, rhs);
// TODO: Just use lhs operand of subscript operator when right hand
// side is a compile-time-known zero value.

IRInstruction *subs_lhs = NULL;
if (lhs->type->kind != TYPE_ARRAY && lhs->type->kind == TYPE_POINTER) {
if (!type_is_array(lhs->type) && !type_is_pointer(lhs->type))
ERR("Subscript operator may only operate on arrays and pointers, which type %T is not", lhs->type);
}

if (lhs->kind == NODE_VARIABLE_REFERENCE) {
// TODO: Handle local variable references, somehow. How can we tell if it's local/static?
subs_lhs = ir_static_reference(ctx, as_span(lhs->var->name));
IRInstruction *var = lhs->var->val.node->ir;
LensPlaysGames marked this conversation as resolved.
Show resolved Hide resolved
// ASSERT(var);
if (var->kind == IR_STATIC_REF)
subs_lhs = var;
else if (var->kind == IR_ALLOCA)
subs_lhs = var;
} else if (lhs->kind == NODE_LITERAL && lhs->literal.type == TK_STRING) {
// ctx->ast->strings.data[lhs->literal.string_index];
TODO("IR generation for subscript of string literal");
}
else ERR("LHS of subscript operator has invalid kind %d", lhs->kind);

// TODO: Just use lhs operand of subscript operator when right hand
// side is a compile-time-known zero value.
codegen_expr(ctx, rhs);

IRInstruction *scaled_rhs = NULL;
// An array subscript needs multiplied by the sizeof the array's base type.
if (lhs->type->kind == TYPE_ARRAY) {
if (type_is_array(lhs->type)) {
IRInstruction *immediate = ir_immediate(ctx, t_integer, type_sizeof(lhs->type->array.of));
scaled_rhs = ir_mul(ctx, rhs->ir, immediate);
}
// A pointer subscript needs multiplied by the sizeof the pointer's base type.
else if (lhs->type->kind == TYPE_POINTER) {
// A pointer subscript needs multiplied by the sizeof the pointer's base type.
else if (type_is_pointer(lhs->type)) {
IRInstruction *immediate = ir_immediate(ctx, t_integer, type_sizeof(lhs->type->pointer.to));
scaled_rhs = ir_mul(ctx, rhs->ir, immediate);
}
Expand Down Expand Up @@ -473,7 +478,7 @@ static void codegen_expr(CodegenContext *ctx, Node *expr) {
if (expr->literal.type == TK_NUMBER) expr->ir = ir_immediate(ctx, expr->type, expr->literal.integer);
else if (expr->literal.type == TK_STRING) {
// TODO: We should probably set this name earlier, or have some
// way of getting this name from jujst a string index. Static
// way of getting this name from just a string index. Static
// variable is big bad. Valve, pls fix. Literally unplayable.
char buf[48] = {0};
static size_t string_literal_count = 0;
Expand All @@ -492,12 +497,6 @@ static void codegen_expr(CodegenContext *ctx, Node *expr) {
/// 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?
// "I’d just emit a load of the array and have the backend
// deal w/ copying 1000 ints." ~ Sirraide
if (expr->ir->type->kind == TYPE_ARRAY)
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
5 changes: 3 additions & 2 deletions src/codegen/intermediate_representation.c
Original file line number Diff line number Diff line change
Expand Up @@ -645,14 +645,15 @@ IRInstruction *ir_create_static(CodegenContext *context, Type *type, span name)
return ref;
}

/// NOTE: Currently unused, but can be used to load a static reference
/// more than once without generating duplicate static variables.
IRInstruction *ir_static_reference(CodegenContext *context, span name) {
Copy link
Contributor

Choose a reason for hiding this comment

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

This probably should not be by name; rather, we should just pass the variable itself here and it would return its ref instead. Not sure where this is used or if there is a good reason why we aren’t doing that, but that’s what I’d do.

Copy link
Owner Author

Choose a reason for hiding this comment

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

What is "the variable itself" here?

Copy link
Contributor

Choose a reason for hiding this comment

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

The IRStaticVariable* or whatever it’s called

Copy link
Owner Author

@LensPlaysGames LensPlaysGames Feb 6, 2023

Choose a reason for hiding this comment

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

How would we go about getting the IRStaticVariable from a variable reference AST node, if not by name?

Copy link
Contributor

Choose a reason for hiding this comment

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

See one of my other comments in codegen.c just now

Copy link
Owner Author

@LensPlaysGames LensPlaysGames Feb 7, 2023

Choose a reason for hiding this comment

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

As it turns out, now that the backend is working better with order of operands and such, we can also just use subs_lhs = var instead of subs_lhs = ir_static_reference(...). So we may actually be able to remove this.

Tangent: doing this has made me realise what stack spilling is and why it's needed; you can save a value on the stack and then just load it into a register vs keeping that register around for as long as it's needed, freeing up more registers for other things. That's exactly what I implemented in the codegen of the IR for static refs, in order to get around botched use of a working RA. Lol.

Relevant code:
https://github.com/LensPlaysGames/FUNCompiler/blob/1104d937a70f065746b8b8e9a1773152e7811ed0/src/codegen.c#L373-L383

Copy link
Owner Author

Choose a reason for hiding this comment

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

Copy link
Contributor

Choose a reason for hiding this comment

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

As it turns out, now that the backend is working better with order of operands and such, we can also just use subs_lhs = var instead of subs_lhs = ir_static_reference(...)

Yeah, in that branch, the var is already a static ref, so you can just reuse that one. That’s pretty much what I meant with ‘you don’t have to look up variables by name’.

if (var->kind == IR_STATIC_REF) 
     subs_lhs = var; 
else if (var->kind == IR_ALLOCA) 
     subs_lhs = var;

I think this could just be

if (var->kind == IR_STATIC_REF || var->kind == IR_ALLOCA)
    subs_lhs = var;

foreach_ptr(IRStaticVariable *, v, context->static_vars) {
if (string_eq(v->name, name)) {
INSTRUCTION(ref, IR_STATIC_REF);
ref->static_ref = v;
ref->type = ast_make_type_pointer(context->ast, v->type->source_location, v->type);
// TODO: `v->reference` may need to become list of references? I think this is why
// optimisation is broken.
// TODO: `v->reference` may need to become list of references?
Copy link
Contributor

@Sirraide Sirraide Feb 7, 2023

Choose a reason for hiding this comment

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

Well the original idea was that there would ever only be one IR_STATIC_REF for each static variable. That’s why there simply was no ir_create_static_ref(), simply because the idea of such an operation would have been flawed to begin with, at least when I wrote this.

Copy link
Owner Author

Choose a reason for hiding this comment

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

Interesting; so there's only some confusion in the fact that IR_STATIC_REF both creates a static as well as holds a reference to an existing static (it's address), in the same way that ALLOCA does. However, can't a static be referenced from multiple scopes? If so, won't each one need a reference to the static? Maybe I'm thinking about this the wrong way

Copy link
Contributor

@Sirraide Sirraide Feb 7, 2023

Choose a reason for hiding this comment

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

When you create a static variable, it creates an IRStaticVariable, which is added to a vector in the context and it’s how the variables are emitted by the backend. This structure holds information about e.g. the name of a static variable:
https://github.com/LensPlaysGames/FUNCompiler/blob/8282edc50843fc5ec882469198e1aedb149dd46e/src/codegen.h#L40-L44

By contrast, an IR_STATIC_REF is an instruction that wraps an IRStaticVariable, in the same way that an IR_ALLOCA wraps an IRStackAllocation. The IRStaticVariable is the variable, the IR_STATIC_REF contains a pointer to that variable. The type of an IR_STATIC_REF is a pointer to whatever the type of the static variable is, for the same reason that the type of an IR_ALLOCA is a pointer to the allocated storage.

The IR_STATIC_REF is just a way to refer to an IRStaticVariable in IR. Only one is needed for each variable as just like the IR_STATIC_REF holds a pointer to the IRStaticVariable, so does the IRStaticVariable contain a pointer to its IR_STATIC_REF. This is why the (not ‘a’) IR_STATIC_REF for a static variable is created together with that variable

INSERT(ref);
return ref;
}
Expand Down
16 changes: 8 additions & 8 deletions src/codegen/x86_64/arch_x86_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -928,8 +928,8 @@ static void emit_instruction(CodegenContext *context, IRInstruction *inst) {
case IR_EQ: codegen_comparison(context, COMPARE_EQ, inst->lhs->result, inst->rhs->result, inst->result); break;
case IR_NE: codegen_comparison(context, COMPARE_NE, inst->lhs->result, inst->rhs->result, inst->result); break;
case IR_ADD:
femit_reg_to_reg(context, I_ADD, inst->rhs->result, inst->lhs->result);
femit_reg_to_reg(context, I_MOV, inst->lhs->result, inst->result);
femit_reg_to_reg(context, I_ADD, inst->lhs->result, inst->rhs->result);
femit_reg_to_reg(context, I_MOV, inst->rhs->result, inst->result);
break;
case IR_SUB:
femit_reg_to_reg(context, I_SUB, inst->rhs->result, inst->lhs->result);
Expand Down Expand Up @@ -988,7 +988,7 @@ static void emit_instruction(CodegenContext *context, IRInstruction *inst) {
enum RegSize size = -1;
// TODO: Should this array to pointer decay happen here? Or higher up in codegen?
if (inst->operand->type->kind == TYPE_ARRAY || inst->operand->type->pointer.to->kind == TYPE_ARRAY)
size = regsize_from_bytes(type_sizeof(t_pointer));
size = regsize_from_bytes(type_sizeof(t_void_ptr));
else size = regsize_from_bytes(type_sizeof(inst->operand->type));
// TODO: Use `movzx`/`movzbl`
if (size == r8 || size == r16) femit_reg_to_reg(context, I_XOR, inst->result, inst->result);
Expand All @@ -1004,7 +1004,7 @@ static void emit_instruction(CodegenContext *context, IRInstruction *inst) {
enum RegSize size = -1;
// TODO: Should this array to pointer decay happen here? Or higher up in codegen?
if (inst->operand->type->kind == TYPE_ARRAY || inst->operand->type->pointer.to->kind == TYPE_ARRAY)
size = regsize_from_bytes(type_sizeof(t_pointer));
size = regsize_from_bytes(type_sizeof(t_void_ptr));
else size = regsize_from_bytes(inst->operand->alloca.size);
// TODO: Use `movzx`/`movzbl`
if (size == r8 || size == r16) femit_reg_to_reg(context, I_XOR, inst->result, inst->result);
Expand All @@ -1018,7 +1018,7 @@ static void emit_instruction(CodegenContext *context, IRInstruction *inst) {
else {
enum RegSize size = -1;
// TODO: Should this array to pointer decay happen here? Or higher up in codegen?
if (inst->operand->type->kind == TYPE_ARRAY) size = regsize_from_bytes(type_sizeof(t_pointer));
if (inst->operand->type->kind == TYPE_ARRAY) size = regsize_from_bytes(type_sizeof(t_void_ptr));
// TODO: We are "supposed" to be loading sizeof pointed to type
// here, but that causes segfaults when handling arrays.
else size = regsize_from_bytes(type_sizeof(inst->operand->type));
Expand Down Expand Up @@ -1165,14 +1165,14 @@ Clobbers does_clobber(IRInstruction *instruction) {
case IR_DIV:
case IR_MUL:
case IR_MOD:
case IR_SHL:
case IR_SHR:
case IR_SAR:
case IR_AND:
case IR_OR:
return CLOBBERS_RIGHT;

case IR_SUB:
case IR_SHL:
case IR_SHR:
case IR_SAR:
return CLOBBERS_LEFT;

case IR_NOT:
Expand Down
4 changes: 3 additions & 1 deletion src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ int handle_command_line_arguments(int argc, char **argv) {
print_acceptable_formats();
return 1;
}
} else if (strcmp(argument, "--colours") == 0) {
} else if (strcmp(argument, "--colours") == 0 || strcmp(argument, "--colors") == 0) {
i++;
if (i >= argc) {
fprint(stderr, "Error: Expected option value after `--colours`\n");
Expand Down Expand Up @@ -269,6 +269,8 @@ int main(int argc, char **argv) {
if (len >= 3 && memcmp(infile + len - 3, ".ir", 3) == 0) {
ASSERT(s.data);

TODO("Development of IR parser and codegen is severely behind right now.");

if (!codegen(
LANG_IR,
output_format,
Expand Down
6 changes: 2 additions & 4 deletions src/parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,6 @@ static void next_token(Parser *p) {
if (isstart(p->lastc)) {
next_identifier(p);

/// Check if the identifier is a keyword.
for (size_t i = 0; i < sizeof keywords / sizeof *keywords; i++) {
if (string_eq(keywords[i].kw, p->tok.text)) {
p->tok.type = keywords[i].type;
Expand Down Expand Up @@ -1074,14 +1073,13 @@ static Node *parse_expr_with_precedence(Parser *p, isz current_precedence) {
if (prec == current_precedence && !is_right_associative(p, p->tok)) return lhs;

/// Otherwise, we need to parse the RHS.
u32 start = p->tok.source_location.start;
enum TokenType tt = p->tok.type;
next_token(p);

/// The `as` operator is special because its RHS is a type.
if (tt == TK_AS) {
Type *type = parse_type(p);
lhs = ast_make_cast(p->ast, (loc){.start = start, .end = type->source_location.end}, type, lhs);
lhs = ast_make_cast(p->ast, (loc){.start = lhs->source_location.start, .end = type->source_location.end}, type, lhs);
continue;
}

Expand All @@ -1090,7 +1088,7 @@ static Node *parse_expr_with_precedence(Parser *p, isz current_precedence) {
Node *rhs = parse_expr_with_precedence(p, prec);

/// Combine the LHS and RHS into a binary expression.
lhs = ast_make_binary(p->ast, (loc){.start = start, .end = rhs->source_location.end}, tt, lhs, rhs);
lhs = ast_make_binary(p->ast, (loc){.start = lhs->source_location.start, .end = rhs->source_location.end}, tt, lhs, rhs);
}
}
}
Expand Down
21 changes: 13 additions & 8 deletions src/typechecker.c
Original file line number Diff line number Diff line change
Expand Up @@ -200,10 +200,10 @@ NODISCARD static Type *common_type(Type *a, Type *b) {
}

/// Check if a type is a pointer type.
NODISCARD static bool is_pointer(Type *type) { return type->kind == TYPE_POINTER; }
NODISCARD static bool is_pointer(Type *type) { return type_is_pointer(type); }

/// Check if a type is an array type.
NODISCARD static bool is_array(Type *type) { return type->kind == TYPE_ARRAY; }
NODISCARD static bool is_array(Type *type) { return type_is_array(type); }
LensPlaysGames marked this conversation as resolved.
Show resolved Hide resolved

/// Check if an expression is an lvalue.
NODISCARD static bool is_lvalue(Node *expr) {
Expand Down Expand Up @@ -789,10 +789,15 @@ NODISCARD bool typecheck_expression(AST *ast, Node *expr) {
/// Make sure the return type of the body is convertible to that of the function.
Type *ret = expr->type->function.return_type;
Type *body = expr->function.body->type;
if (!convertible(ret, body))
ERR(expr->source_location,
"Type '%T' of function body is not convertible to return type '%T'.",
ret, body);
if (!convertible(ret, body)) {
loc l = {0};
if (expr->function.body->kind == NODE_BLOCK)
l = vector_back_or(expr->function.body->block.children, expr)->source_location;
else l = expr->function.body->source_location;
ERR(l,
"Type '%T' of function body is not convertible to return type '%T'.",
body, ret);
}
} break;

/// Typecheck declarations.
Expand Down Expand Up @@ -906,10 +911,10 @@ NODISCARD bool typecheck_expression(AST *ast, Node *expr) {
if (types_equal(t_to, t_from)) break;

// FROM any incomplete type is DISALLOWED
if (type_is_incomplete(t_from) || type_is_incomplete(t_to))
if (type_is_incomplete(t_from))
ERR(expr->cast.value->source_location, "Can not cast from an incomplete type %T", t_from);
// TO any complete type is DISALLOWED
if (type_is_incomplete(t_from) || type_is_incomplete(t_to))
if (type_is_incomplete(t_to))
ERR(expr->cast.value->source_location, "Can not cast to an incomplete type %T", t_to);

// FROM any pointer type TO any pointer type is ALLOWED
Expand Down
3 changes: 3 additions & 0 deletions tst/tests/shiftleft.un
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
; 8

2 << 2
3 changes: 3 additions & 0 deletions tst/tests/shiftright.un
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
; 2

8 >> 2