-
Notifications
You must be signed in to change notification settings - Fork 2
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
Array compound generation first pass #57
Open
BrettRToomey
wants to merge
11
commits into
rewrite
Choose a base branch
from
array-compound
base: rewrite
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 9 commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
9135158
Array compound generation first pass
BrettRToomey 948c2d9
Merge branch 'rewrite' into array-compound
BrettRToomey 89fd2e8
Cleaned up whitespace
BrettRToomey a8a1970
Tabs to spaces
BrettRToomey 79a72b6
Fixed most formatting errors
BrettRToomey e1f7be8
Even more whitespace fixes
BrettRToomey aa5c50c
Fixed switch formatting
BrettRToomey 56e6163
Fixed ugly xcode formatting
BrettRToomey f824a88
Minimize diff against master
vdka 55baeee
Default to zero value instead of undef, cleanup dead comment
vdka 69b820c
Merge branch 'rewrite' into array-compound
BrettRToomey File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,6 +22,7 @@ extern "C" { | |
#include <llvm/IR/Constants.h> | ||
#include <llvm/IR/DerivedTypes.h> | ||
#include <llvm/IR/Function.h> | ||
#include <llvm/IR/Intrinsics.h> | ||
#include <llvm/IR/IRBuilder.h> | ||
#include <llvm/IR/LLVMContext.h> | ||
#include <llvm/IR/Module.h> | ||
|
@@ -342,7 +343,8 @@ Type *llvm_type(IRContext *c, Ty *type, bool do_not_hide_behind_pointer = false) | |
case TYPE_ARRAY: { | ||
Type *base = llvm_type(c, type->tarray.eltype); | ||
Type *ty = ArrayType::get(base, type->tarray.length); | ||
return ty; | ||
if (do_not_hide_behind_pointer) return ty; | ||
return PointerType::get(ty, 0); | ||
} | ||
case TYPE_SLICE: { | ||
if (type == type_string) return c->ty.rawptr; // FIXME: Temp hack while we don't have slices | ||
|
@@ -364,7 +366,7 @@ Type *llvm_type(IRContext *c, Ty *type, bool do_not_hide_behind_pointer = false) | |
if (type->sym) { | ||
const char *name = type->sym->external_name ?: type->sym->name; | ||
StructType *ty = StructType::create(c->context, elements, name); | ||
if (type->sym) type->sym->userdata = ty; | ||
type->sym->userdata = ty; | ||
return ty; | ||
} | ||
return StructType::get(c->context, elements); | ||
|
@@ -457,7 +459,7 @@ DIType *llvm_debug_type(IRContext *c, Ty *type, bool do_not_hide_behind_pointer | |
subscripts.push_back(c->dbg.builder->getOrCreateSubrange(0, eltype->tarray.length)); | ||
eltype = eltype->tarray.eltype; | ||
} | ||
Type *irtype = llvm_type(c, type); | ||
Type *irtype = llvm_type(c, type, true); | ||
u64 size = c->data_layout.getTypeSizeInBits(irtype); | ||
u32 align = c->data_layout.getPrefTypeAlignment(irtype) * 8; | ||
DIType *deltype = llvm_debug_type(c, type->tarray.eltype); | ||
|
@@ -745,7 +747,7 @@ Value *create_coerce(IRContext *self, Value *val, Expr *expr, bool is_lvalue = f | |
goto start; | ||
} | ||
if (isa<FunctionType>(val_ty)) return val; | ||
if (val_ty->getPointerElementType() == dst_ty) return create_load(self, val); // FIXME: Do not do this.... | ||
|
||
// FIXME: IF isa<ArrayType> What do? | ||
return self->builder.CreatePointerBitCastOrAddrSpaceCast(val, dst_ty); | ||
} | ||
|
@@ -965,29 +967,21 @@ IRValue emit_expr_compound(IRContext *self, Expr *expr) { | |
} | ||
case TYPE_ARRAY: { | ||
Type *eltype = llvm_type(self, operand.type->tarray.eltype); | ||
ArrayType *type = (ArrayType *) llvm_type(self, operand.type); | ||
ArrayType *type = (ArrayType *) llvm_type(self, operand.type, true); | ||
|
||
Value *agg = Constant::getNullValue(type); | ||
u32 index = 0; | ||
for (i64 i = 0; i < arrlen(expr->ecompound.fields); i++) { | ||
Value *val = emit_expr(self, expr->ecompound.fields[i].val).val; | ||
if (expr->ecompound.fields[i].key) { | ||
Operand op = hmget(self->package->operands, expr->ecompound.fields[i].key); | ||
index = (u32) op.val.u; | ||
} | ||
agg = self->builder.CreateInsertValue(agg, val, index); | ||
index++; | ||
} | ||
return irval(agg); | ||
|
||
if (!expr->ecompound.fields) | ||
return irval(agg); | ||
|
||
Value *value; | ||
if (!expr->ecompound.fields) return irval(value); | ||
bool is_all_members_constant = true; | ||
bool does_have_gaps = operand.type->tarray.length != arrlen(expr->ecompound.fields); | ||
|
||
std::vector<Value *> values; | ||
std::vector<Constant *> constants; | ||
for (i64 i = 0; i < arrlen(expr->ecompound.fields); i++) { | ||
Value *el = emit_expr(self, expr->ecompound.fields[i].val).val; | ||
is_all_members_constant |= isa<Constant>(el); | ||
is_all_members_constant &= isa<Constant>(el); | ||
if (Constant *constant = dyn_cast<Constant>(el)) { | ||
constants.push_back(constant); | ||
} else { | ||
|
@@ -996,45 +990,60 @@ IRValue emit_expr_compound(IRContext *self, Expr *expr) { | |
} | ||
values.push_back(el); | ||
} | ||
u32 alignment = self->data_layout.getPrefTypeAlignment(type); | ||
// FIXME: can't do this if we aren't in a function. | ||
Constant *constant = ConstantArray::get(type, constants); | ||
return irval(constant); | ||
|
||
if (constant->isZeroValue()) { | ||
GlobalVariable *global = new GlobalVariable( | ||
*self->module, type, true, GlobalValue::PrivateLinkage, constant, | ||
"compound.lit"); | ||
return irval(global); | ||
|
||
if (!self->fn) { | ||
return irval(llvm::ConstantArray::get(type, constants)); | ||
} | ||
|
||
u32 alignment = self->data_layout.getPrefTypeAlignment(type); | ||
u32 size = (u32)self->data_layout.getTypeStoreSize(type); | ||
|
||
AllocaInst *alloca = emit_entry_alloca(self, type, "compound.lit", alignment); | ||
|
||
if (is_all_members_constant) { | ||
u64 target_index = 0; | ||
for (i64 i = 0; i < arrlen(expr->ecompound.fields); i++) { | ||
CompoundField field = expr->ecompound.fields[i]; | ||
u64 target_index = hmget(self->package->operands, field.key).val.u; | ||
value = self->builder.CreateInsertValue(value, values[i], {(u32) target_index}); | ||
} | ||
if (isa<Constant>(value)) { | ||
GlobalVariable *global = new GlobalVariable( | ||
*self->module, type, true, GlobalValue::PrivateLinkage, (Constant *)value, | ||
"compound.lit"); | ||
self->builder.CreateMemCpy( | ||
alloca, alignment, global, global->getAlignment(), | ||
type->getPrimitiveSizeInBits() / 8); | ||
value = alloca; | ||
} else { | ||
// create_store(self, value, alloca); | ||
if (field.kind == FIELD_INDEX) { | ||
target_index = (u32) hmget(self->package->operands, field.key).val.u; | ||
} | ||
|
||
agg = self->builder.CreateInsertValue(agg, constants[i], {(u32)target_index}); | ||
target_index++; | ||
} | ||
|
||
GlobalVariable *global = new GlobalVariable( | ||
*self->module, type, true, GlobalValue::PrivateLinkage, (Constant *)agg, | ||
"compound.lit"); | ||
|
||
self->builder.CreateMemCpy( | ||
alloca, alignment, global, global->getAlignment(), size); | ||
} else { | ||
// NOTE: memset requires `zero` to be a char | ||
llvm::Value *zero = llvm::ConstantInt::get(self->ty.i8, 0); | ||
llvm::Value *element = self->builder.CreateInBoundsGEP(alloca, {zero, zero}); | ||
|
||
if (does_have_gaps) { | ||
self->builder.CreateMemSet(alloca, zero, size, alignment); | ||
} | ||
|
||
u64 target_index = 0; | ||
|
||
for (i64 i = 0; i < arrlen(expr->ecompound.fields); i++) { | ||
CompoundField field = expr->ecompound.fields[i]; | ||
u64 target_index = hmget(self->package->operands, field.key).val.u; | ||
value = self->builder.CreateInsertValue( | ||
alloca, values[i], {0, (u32) target_index}); | ||
if (field.kind == FIELD_INDEX) { | ||
target_index = (u32) hmget(self->package->operands, field.key).val.u; | ||
} | ||
|
||
llvm::Value *offset = llvm::ConstantInt::get(self->ty.i64, target_index); | ||
self->builder.CreateInBoundsGEP(element, offset); | ||
create_store(self, values[i], element); | ||
|
||
target_index++; | ||
} | ||
} | ||
return irval(alloca); | ||
|
||
return irval(alloca, true); | ||
} | ||
case TYPE_SLICE: | ||
default: | ||
|
@@ -1209,7 +1218,7 @@ IRValue emit_expr_call(IRContext *self, Expr *expr) { | |
if (is_cvargs && last_arg) { // C ABI rules (TODO: Apply to all parameters for c calls) | ||
if (is_integer(arg_operand.type) && arg_operand.type->size < 4) { | ||
val = is_signed(arg_operand.type) ? | ||
self->builder.CreateSExt(val, self->ty.i32) : self->builder.CreateZExt(val, self->ty.u32); | ||
self->builder.CreateSExt(val, self->ty.i32) : self->builder.CreateZExt(val, self->ty.u32); | ||
} else if (is_float(arg_operand.type) && arg_operand.type->size < 8) { | ||
self->builder.CreateFPExt(val, self->ty.f64); | ||
} | ||
|
@@ -1249,6 +1258,12 @@ IRValue emit_expr_index(IRContext *self, Expr *expr) { | |
|
||
IRValue emit_expr_slice(IRContext *self, Expr *expr) { return {}; } | ||
|
||
IRValue emit_expr_struct(IRContext *self, Expr *expr) { | ||
Operand operand = hmget(self->package->operands, expr); | ||
llvm::StructType *type = (llvm::StructType *) llvm_type(self, operand.type); | ||
return irval((Value *)type); | ||
} | ||
|
||
IRValue emit_expr_func(IRContext *self, Expr *expr) { | ||
TRACE(EMITTING); | ||
Operand operand = hmget(self->package->operands, expr); | ||
|
@@ -1374,7 +1389,6 @@ IRValue emit_expr_functype(IRContext *self, Expr *expr) { fatal("Unimplemented % | |
IRValue emit_expr_slicetype(IRContext *self, Expr *expr) { fatal("Unimplemented %s", __FUNCTION__); } | ||
IRValue emit_expr_array(IRContext *self, Expr *expr) { fatal("Unimplemented %s", __FUNCTION__); } | ||
IRValue emit_expr_pointer(IRContext *self, Expr *expr) { fatal("Unimplemented %s", __FUNCTION__); } | ||
IRValue emit_expr_struct(IRContext *self, Expr *expr) { fatal("Unimplemented %s", __FUNCTION__); } | ||
IRValue emit_expr_union(IRContext *self, Expr *expr) { fatal("Unimplemented %s", __FUNCTION__); } | ||
IRValue emit_expr_enum(IRContext *self, Expr *expr) { fatal("Unimplemented %s", __FUNCTION__); } | ||
|
||
|
@@ -1767,7 +1781,7 @@ void emit_decl_var_global(IRContext *self, Decl *decl) { | |
} else { | ||
init = Constant::getNullValue(llvm_type(self, sym->type)); | ||
} | ||
Type *type = llvm_type(self, sym->type); | ||
Type *type = llvm_type(self, sym->type, true); | ||
GlobalVariable *global = new GlobalVariable( | ||
*self->module, type, /* IsConstant */ false, GlobalValue::ExternalLinkage, | ||
init, sym->external_name ?: sym->name); | ||
|
@@ -1829,16 +1843,26 @@ void emit_decl_var(IRContext *self, Decl *decl) { | |
return; | ||
} | ||
} | ||
Type *type = llvm_type(self, sym->type); | ||
|
||
Type *type = llvm_type(self, sym->type, true); | ||
|
||
Value *alloca; | ||
if (rhs_is_alloca) { | ||
alloca = rhs; | ||
} else { | ||
// FIXME: Alloca can't happen at global scope instead use a global variable and add | ||
// check that we only initialize with global variables. | ||
alloca = emit_entry_alloca(self, type, sym->name, sym->type->align); | ||
if (rhs) create_coerced_store(self, rhs, alloca); | ||
if (self->fn) { | ||
alloca = emit_entry_alloca(self, type, sym->name, sym->type->align); | ||
if (rhs) create_coerced_store(self, rhs, alloca); | ||
} else { | ||
GlobalVariable *global = new GlobalVariable( | ||
*self->module, type, false, GlobalValue::ExternalLinkage, (Constant *)rhs, | ||
sym->external_name ?: sym->name); | ||
global->setAlignment(sym->type->align); | ||
global->setExternallyInitialized(false); | ||
alloca = global; | ||
} | ||
} | ||
sym->userdata = alloca; | ||
set_debug_pos(self, name->range); | ||
|
@@ -1856,7 +1880,7 @@ void emit_decl_val(IRContext *self, Decl *decl) { | |
arrpush(self->symbols, sym); | ||
Value *value = emit_expr(self, decl->dval.val).val; | ||
arrpop(self->symbols); | ||
if (isa<Function>(value)) { | ||
if (isa<Function>(value) || isa<StructType>((Type *)value)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is bad |
||
sym->userdata = value; | ||
return; | ||
} | ||
|
@@ -2170,3 +2194,4 @@ void print(Module *module) { | |
puts(buf.c_str()); | ||
} | ||
#endif | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
testArray := [3]i32 { 1, 2, 3 } | ||
|
||
test :: fn(b: i32) -> void { | ||
a := [..]i32 { 0, 1, 2, 3} | ||
} | ||
|
||
main :: fn() -> void { | ||
a := 11 | ||
b := a + 11 | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems like I need the
true
here for global variables but I'm not exactly sure if I need it for all cases. Thoughts?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That makes sense for array's, a Global Variable needs the raw type so it know's how much space to reserve, this actually will cause an error for functions though,
llvm_type
will return a FunctionType for functions, this will cause an assert in LLVM when it attempts to work out a size for the global.I guess maybe we need
llvm_type
's hide behind pointer to be a mask maybe? Something likellvm_type(self, sym->type, ARRAY | STRUCT)
and inemit_expr_func
we would havellvm_type(self, type, FUNCTION)