mirror of
https://github.com/ziglang/zig.git
synced 2026-02-15 13:58:27 +00:00
IR: correctly codegening memset and memcpy
This commit is contained in:
parent
bf7cde62c5
commit
d94cb0566b
@ -404,7 +404,7 @@ Function Operation
|
||||
@shlWithOverflow(inline T: type, a: T, b: T, result: &T) -> bool *x = a << b
|
||||
```
|
||||
|
||||
### @memset(dest, c: u8, byte_count: usize)
|
||||
### @memset(dest: &T, c: u8, byte_count: usize)
|
||||
|
||||
This function sets a region of memory to `c`. `dest` is a pointer.
|
||||
|
||||
@ -412,11 +412,10 @@ This function is a low level intrinsic with no safety mechanisms. Most higher
|
||||
level code will not use this function, instead using something like this:
|
||||
|
||||
```zig
|
||||
// assume dest is a slice
|
||||
for (dest) |*b| *b = c;
|
||||
for (destSlice) |*b| *b = c;
|
||||
```
|
||||
|
||||
### @memcpy(dest, source, byte_count: usize)
|
||||
### @memcpy(noalias dest: &T, noalias source: &const T, byte_count: usize)
|
||||
|
||||
This function copies bytes from one region of memory to another. `dest` and
|
||||
`source` are both pointers and must not overlap.
|
||||
@ -426,8 +425,7 @@ level code will not use this function, instead using something like this:
|
||||
|
||||
```zig
|
||||
const mem = @import("std").mem;
|
||||
// assume dest and source are slices
|
||||
mem.copy(dest, source);
|
||||
mem.copy(destSlice, sourceSlice);
|
||||
```
|
||||
|
||||
### @breakpoint()
|
||||
|
||||
@ -870,7 +870,6 @@ uint32_t generic_fn_type_id_hash(GenericFnTypeId *id);
|
||||
bool generic_fn_type_id_eql(GenericFnTypeId *a, GenericFnTypeId *b);
|
||||
|
||||
|
||||
static const size_t fn_type_id_prealloc_param_info_count = 4;
|
||||
struct FnTypeId {
|
||||
TypeTableEntry *return_type;
|
||||
FnTypeParamInfo *param_info;
|
||||
@ -879,7 +878,6 @@ struct FnTypeId {
|
||||
bool is_naked;
|
||||
bool is_cold;
|
||||
bool is_extern;
|
||||
FnTypeParamInfo prealloc_param_info[fn_type_id_prealloc_param_info_count];
|
||||
};
|
||||
|
||||
uint32_t fn_type_id_hash(FnTypeId*);
|
||||
|
||||
@ -682,9 +682,6 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id, bool gen_debug_inf
|
||||
TypeTableEntry *fn_type = new_type_table_entry(TypeTableEntryIdFn);
|
||||
fn_type->deep_const = true;
|
||||
fn_type->data.fn.fn_type_id = *fn_type_id;
|
||||
if (fn_type_id->param_info == &fn_type_id->prealloc_param_info[0]) {
|
||||
fn_type->data.fn.fn_type_id.param_info = &fn_type->data.fn.fn_type_id.prealloc_param_info[0];
|
||||
}
|
||||
|
||||
if (fn_type_id->is_cold) {
|
||||
fn_type->data.fn.calling_convention = LLVMColdCallConv;
|
||||
@ -915,12 +912,7 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor
|
||||
fn_type_id.is_naked = is_naked;
|
||||
fn_type_id.is_cold = is_cold;
|
||||
fn_type_id.param_count = fn_proto->params.length;
|
||||
|
||||
if (fn_type_id.param_count > fn_type_id_prealloc_param_info_count) {
|
||||
fn_type_id.param_info = allocate_nonzero<FnTypeParamInfo>(fn_type_id.param_count);
|
||||
} else {
|
||||
fn_type_id.param_info = &fn_type_id.prealloc_param_info[0];
|
||||
}
|
||||
fn_type_id.param_info = allocate_nonzero<FnTypeParamInfo>(fn_type_id.param_count);
|
||||
|
||||
fn_type_id.is_var_args = fn_proto->is_var_args;
|
||||
fn_type_id.return_type = analyze_type_expr(g, import, context, fn_proto->return_type);
|
||||
|
||||
@ -1483,7 +1483,8 @@ static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutable *executable, IrIn
|
||||
}
|
||||
|
||||
static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrInstructionElemPtr *instruction) {
|
||||
LLVMValueRef array_ptr = ir_llvm_value(g, instruction->array_ptr);
|
||||
LLVMValueRef array_ptr_ptr = ir_llvm_value(g, instruction->array_ptr);
|
||||
LLVMValueRef array_ptr = LLVMBuildLoad(g->builder, array_ptr_ptr, "");
|
||||
LLVMValueRef subscript_value = ir_llvm_value(g, instruction->elem_index);
|
||||
TypeTableEntry *array_type = instruction->array_ptr->type_entry;
|
||||
return gen_array_elem_ptr(g, instruction->base.source_node, array_ptr, array_type, subscript_value);
|
||||
@ -3265,19 +3266,6 @@ static void get_c_type(CodeGen *g, TypeTableEntry *type_entry, Buf *out_buf) {
|
||||
}
|
||||
}
|
||||
|
||||
static void get_c_type_node(CodeGen *g, AstNode *type_node, Buf *out_buf) {
|
||||
Expr *expr = get_resolved_expr(type_node);
|
||||
assert(expr->instruction->type_entry);
|
||||
assert(expr->instruction->type_entry->id == TypeTableEntryIdMetaType);
|
||||
|
||||
ConstExprValue *const_val = &expr->instruction->static_value;
|
||||
assert(const_val->special != ConstValSpecialRuntime);
|
||||
|
||||
TypeTableEntry *type_entry = const_val->data.x_type;
|
||||
|
||||
return get_c_type(g, type_entry, out_buf);
|
||||
}
|
||||
|
||||
void codegen_generate_h_file(CodeGen *g) {
|
||||
assert(!g->is_test_build);
|
||||
|
||||
@ -3303,25 +3291,27 @@ void codegen_generate_h_file(CodeGen *g) {
|
||||
if (fn_proto->top_level_decl.visib_mod != VisibModExport)
|
||||
continue;
|
||||
|
||||
FnTypeId *fn_type_id = &fn_table_entry->type_entry->data.fn.fn_type_id;
|
||||
Buf return_type_c = BUF_INIT;
|
||||
get_c_type(g, fn_table_entry->type_entry->data.fn.fn_type_id.return_type, &return_type_c);
|
||||
get_c_type(g, fn_type_id->return_type, &return_type_c);
|
||||
|
||||
buf_appendf(&h_buf, "%s %s %s(",
|
||||
buf_ptr(export_macro),
|
||||
buf_ptr(&return_type_c),
|
||||
buf_ptr(fn_proto->name));
|
||||
buf_ptr(&fn_table_entry->symbol_name));
|
||||
|
||||
Buf param_type_c = BUF_INIT;
|
||||
if (fn_proto->params.length) {
|
||||
for (size_t param_i = 0; param_i < fn_proto->params.length; param_i += 1) {
|
||||
if (fn_type_id->param_count > 0) {
|
||||
for (size_t param_i = 0; param_i < fn_type_id->param_count; param_i += 1) {
|
||||
FnTypeParamInfo *param_info = &fn_type_id->param_info[param_i];
|
||||
AstNode *param_decl_node = fn_proto->params.at(param_i);
|
||||
AstNode *param_type = param_decl_node->data.param_decl.type;
|
||||
get_c_type_node(g, param_type, ¶m_type_c);
|
||||
buf_appendf(&h_buf, "%s %s",
|
||||
buf_ptr(¶m_type_c),
|
||||
buf_ptr(param_decl_node->data.param_decl.name));
|
||||
if (param_i < fn_proto->params.length - 1)
|
||||
buf_appendf(&h_buf, ", ");
|
||||
Buf *param_name = param_decl_node->data.param_decl.name;
|
||||
|
||||
const char *comma_str = (param_i == 0) ? "" : ", ";
|
||||
const char *restrict_str = param_info->is_noalias ? "restrict" : "";
|
||||
get_c_type(g, param_info->type, ¶m_type_c);
|
||||
buf_appendf(&h_buf, "%s%s%s %s", comma_str, buf_ptr(¶m_type_c),
|
||||
restrict_str, buf_ptr(param_name));
|
||||
}
|
||||
buf_appendf(&h_buf, ")");
|
||||
} else {
|
||||
|
||||
@ -36,6 +36,7 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockCont
|
||||
static TypeTableEntry *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *instruction);
|
||||
|
||||
ConstExprValue *const_ptr_pointee(ConstExprValue *const_val) {
|
||||
assert(const_val->special == ConstValSpecialStatic);
|
||||
ConstExprValue *base_ptr = const_val->data.x_ptr.base_ptr;
|
||||
size_t index = const_val->data.x_ptr.index;
|
||||
|
||||
@ -3620,7 +3621,6 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
|
||||
assert(ptr_type->id == TypeTableEntryIdPointer);
|
||||
|
||||
TypeTableEntry *array_type = ptr_type->data.pointer.child_type;
|
||||
ConstExprValue *array_ptr_val = const_ptr_pointee(&array_ptr->static_value);
|
||||
TypeTableEntry *return_type;
|
||||
|
||||
if (array_type->id == TypeTableEntryIdInvalid) {
|
||||
@ -3659,7 +3659,11 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
|
||||
}
|
||||
}
|
||||
|
||||
if (array_ptr_val->special != ConstValSpecialRuntime) {
|
||||
ConstExprValue *array_ptr_val;
|
||||
if (array_ptr->static_value.special != ConstValSpecialRuntime &&
|
||||
(array_ptr_val = const_ptr_pointee(&array_ptr->static_value)) &&
|
||||
array_ptr_val->special != ConstValSpecialRuntime)
|
||||
{
|
||||
bool depends_on_compile_var = array_ptr_val->depends_on_compile_var ||
|
||||
casted_elem_index->static_value.depends_on_compile_var;
|
||||
ConstExprValue *out_val = ir_build_const_from(ira, &elem_ptr_instruction->base, depends_on_compile_var);
|
||||
|
||||
@ -602,12 +602,7 @@ static TypeTableEntry *resolve_type_with_table(Context *c, const Type *ty, const
|
||||
}
|
||||
}
|
||||
|
||||
if (fn_type_id.param_count > fn_type_id_prealloc_param_info_count) {
|
||||
fn_type_id.param_info = allocate_nonzero<FnTypeParamInfo>(fn_type_id.param_count);
|
||||
} else {
|
||||
fn_type_id.param_info = &fn_type_id.prealloc_param_info[0];
|
||||
}
|
||||
|
||||
fn_type_id.param_info = allocate_nonzero<FnTypeParamInfo>(fn_type_id.param_count);
|
||||
for (size_t i = 0; i < fn_type_id.param_count; i += 1) {
|
||||
QualType qt = fn_proto_ty->getParamType(i);
|
||||
TypeTableEntry *param_type = resolve_qual_type(c, qt, decl);
|
||||
|
||||
@ -1,24 +1,24 @@
|
||||
// These functions are provided when not linking against libc because LLVM
|
||||
// sometimes generates code that calls them.
|
||||
|
||||
// TODO dest should be nullable and return value should be nullable
|
||||
export fn memset(dest: &u8, c: u8, n: usize) -> &u8 {
|
||||
@setDebugSafety(this, false);
|
||||
|
||||
var index: usize = 0;
|
||||
while (index != n) {
|
||||
while (index != n; index += 1)
|
||||
dest[index] = c;
|
||||
index += 1;
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
// TODO dest, source, and return value should be nullable
|
||||
export fn memcpy(noalias dest: &u8, noalias src: &const u8, n: usize) -> &u8 {
|
||||
@setDebugSafety(this, false);
|
||||
|
||||
var index: usize = 0;
|
||||
while (index != n) {
|
||||
while (index != n; index += 1)
|
||||
dest[index] = src[index];
|
||||
index += 1;
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user