aboutsummaryrefslogtreecommitdiff
path: root/src/codegen.cpp
diff options
context:
space:
mode:
authorAndrew Kelley <superjoe30@gmail.com>2018-12-23 17:04:26 -0500
committerAndrew Kelley <superjoe30@gmail.com>2018-12-23 17:04:26 -0500
commitc00216701c64269a2395e84f3ccff99d6fb89ffc (patch)
tree9fa071b9e96f9eadc5069b71634b11fc13b00839 /src/codegen.cpp
parentc21884e1d64e4193e03be4f3064917a26b34b142 (diff)
parent45081c1e9cc28757cb563c77553631f7a92b29d8 (diff)
downloadzig-c00216701c64269a2395e84f3ccff99d6fb89ffc.tar.gz
zig-c00216701c64269a2395e84f3ccff99d6fb89ffc.zip
Merge remote-tracking branch 'origin/master' into llvm8
Diffstat (limited to 'src/codegen.cpp')
-rw-r--r--src/codegen.cpp111
1 files changed, 77 insertions, 34 deletions
diff --git a/src/codegen.cpp b/src/codegen.cpp
index bd9063d020..e37703d5f0 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -129,6 +129,11 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out
Buf *src_dir = buf_alloc();
os_path_split(root_src_path, src_dir, src_basename);
+ if (buf_len(src_basename) == 0) {
+ fprintf(stderr, "Invalid root source path: %s\n", buf_ptr(root_src_path));
+ exit(1);
+ }
+
g->root_package = new_package(buf_ptr(src_dir), buf_ptr(src_basename));
g->std_package = new_package(buf_ptr(g->zig_std_dir), "index.zig");
g->root_package->package_table.put(buf_create_from_str("std"), g->std_package);
@@ -1645,7 +1650,7 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, Z
zig_unreachable();
}
- if (actual_bits >= wanted_bits && actual_type->id == ZigTypeIdInt &&
+ if (actual_type->id == ZigTypeIdInt &&
!wanted_type->data.integral.is_signed && actual_type->data.integral.is_signed &&
want_runtime_safety)
{
@@ -2879,32 +2884,6 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
return cast_instruction->tmp_ptr;
}
- case CastOpBytesToSlice:
- {
- assert(cast_instruction->tmp_ptr);
- assert(wanted_type->id == ZigTypeIdStruct);
- assert(wanted_type->data.structure.is_slice);
- assert(actual_type->id == ZigTypeIdArray);
-
- ZigType *wanted_pointer_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
- ZigType *wanted_child_type = wanted_pointer_type->data.pointer.child_type;
-
-
- size_t wanted_ptr_index = wanted_type->data.structure.fields[0].gen_index;
- LLVMValueRef dest_ptr_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr,
- (unsigned)wanted_ptr_index, "");
- LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, expr_val, wanted_pointer_type->type_ref, "");
- gen_store_untyped(g, src_ptr_casted, dest_ptr_ptr, 0, false);
-
- size_t wanted_len_index = wanted_type->data.structure.fields[1].gen_index;
- LLVMValueRef len_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr,
- (unsigned)wanted_len_index, "");
- LLVMValueRef len_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref,
- actual_type->data.array.len / type_size(g, wanted_child_type), false);
- gen_store_untyped(g, len_val, len_ptr, 0, false);
-
- return cast_instruction->tmp_ptr;
- }
case CastOpIntToFloat:
assert(actual_type->id == ZigTypeIdInt);
if (actual_type->data.integral.is_signed) {
@@ -3660,6 +3639,13 @@ static LLVMValueRef ir_render_asm(CodeGen *g, IrExecutable *executable, IrInstru
AsmOutput *asm_output = asm_expr->output_list.at(i);
bool is_return = (asm_output->return_type != nullptr);
assert(*buf_ptr(asm_output->constraint) == '=');
+ // LLVM uses commas internally to separate different constraints,
+ // alternative constraints are achieved with pipes.
+ // We still allow the user to use commas in a way that is similar
+ // to GCC's inline assembly.
+ // http://llvm.org/docs/LangRef.html#constraint-codes
+ buf_replace(asm_output->constraint, ',', '|');
+
if (is_return) {
buf_appendf(&constraint_buf, "=%s", buf_ptr(asm_output->constraint) + 1);
} else {
@@ -3679,14 +3665,30 @@ static LLVMValueRef ir_render_asm(CodeGen *g, IrExecutable *executable, IrInstru
}
for (size_t i = 0; i < asm_expr->input_list.length; i += 1, total_index += 1, param_index += 1) {
AsmInput *asm_input = asm_expr->input_list.at(i);
+ buf_replace(asm_input->constraint, ',', '|');
IrInstruction *ir_input = instruction->input_list[i];
buf_append_buf(&constraint_buf, asm_input->constraint);
if (total_index + 1 < total_constraint_count) {
buf_append_char(&constraint_buf, ',');
}
- param_types[param_index] = ir_input->value.type->type_ref;
- param_values[param_index] = ir_llvm_value(g, ir_input);
+ ZigType *const type = ir_input->value.type;
+ LLVMTypeRef type_ref = type->type_ref;
+ LLVMValueRef value_ref = ir_llvm_value(g, ir_input);
+ // Handle integers of non pot bitsize by widening them.
+ if (type->id == ZigTypeIdInt) {
+ const size_t bitsize = type->data.integral.bit_count;
+ if (bitsize < 8 || !is_power_of_2(bitsize)) {
+ const bool is_signed = type->data.integral.is_signed;
+ const size_t wider_bitsize = bitsize < 8 ? 8 : round_to_next_power_of_2(bitsize);
+ ZigType *const wider_type = get_int_type(g, is_signed, wider_bitsize);
+ type_ref = wider_type->type_ref;
+ value_ref = gen_widen_or_shorten(g, false, type, wider_type, value_ref);
+ }
+ }
+
+ param_types[param_index] = type_ref;
+ param_values[param_index] = value_ref;
}
for (size_t i = 0; i < asm_expr->clobber_list.length; i += 1, total_index += 1) {
Buf *clobber_buf = asm_expr->clobber_list.at(i);
@@ -3705,8 +3707,8 @@ static LLVMValueRef ir_render_asm(CodeGen *g, IrExecutable *executable, IrInstru
LLVMTypeRef function_type = LLVMFunctionType(ret_type, param_types, (unsigned)input_and_output_count, false);
bool is_volatile = asm_expr->is_volatile || (asm_expr->output_list.length == 0);
- LLVMValueRef asm_fn = LLVMConstInlineAsm(function_type, buf_ptr(&llvm_template),
- buf_ptr(&constraint_buf), is_volatile, false);
+ LLVMValueRef asm_fn = LLVMGetInlineAsm(function_type, buf_ptr(&llvm_template), buf_len(&llvm_template),
+ buf_ptr(&constraint_buf), buf_len(&constraint_buf), is_volatile, false, LLVMInlineAsmDialectATT);
return LLVMBuildCall(g->builder, asm_fn, param_values, (unsigned)input_and_output_count, "");
}
@@ -3786,6 +3788,11 @@ static LLVMValueRef get_int_builtin_fn(CodeGen *g, ZigType *int_type, BuiltinFnI
n_args = 1;
key.id = ZigLLVMFnIdPopCount;
key.data.pop_count.bit_count = (uint32_t)int_type->data.integral.bit_count;
+ } else if (fn_id == BuiltinFnIdBswap) {
+ fn_name = "bswap";
+ n_args = 1;
+ key.id = ZigLLVMFnIdBswap;
+ key.data.bswap.bit_count = (uint32_t)int_type->data.integral.bit_count;
} else {
zig_unreachable();
}
@@ -5070,6 +5077,29 @@ static LLVMValueRef ir_render_sqrt(CodeGen *g, IrExecutable *executable, IrInstr
return LLVMBuildCall(g->builder, fn_val, &op, 1, "");
}
+static LLVMValueRef ir_render_bswap(CodeGen *g, IrExecutable *executable, IrInstructionBswap *instruction) {
+ LLVMValueRef op = ir_llvm_value(g, instruction->op);
+ ZigType *int_type = instruction->base.value.type;
+ assert(int_type->id == ZigTypeIdInt);
+ if (int_type->data.integral.bit_count % 16 == 0) {
+ LLVMValueRef fn_val = get_int_builtin_fn(g, instruction->base.value.type, BuiltinFnIdBswap);
+ return LLVMBuildCall(g->builder, fn_val, &op, 1, "");
+ }
+ // Not an even number of bytes, so we zext 1 byte, then bswap, shift right 1 byte, truncate
+ ZigType *extended_type = get_int_type(g, int_type->data.integral.is_signed,
+ int_type->data.integral.bit_count + 8);
+ // aabbcc
+ LLVMValueRef extended = LLVMBuildZExt(g->builder, op, extended_type->type_ref, "");
+ // 00aabbcc
+ LLVMValueRef fn_val = get_int_builtin_fn(g, extended_type, BuiltinFnIdBswap);
+ LLVMValueRef swapped = LLVMBuildCall(g->builder, fn_val, &extended, 1, "");
+ // ccbbaa00
+ LLVMValueRef shifted = ZigLLVMBuildLShrExact(g->builder, swapped,
+ LLVMConstInt(extended_type->type_ref, 8, false), "");
+ // 00ccbbaa
+ return LLVMBuildTrunc(g->builder, shifted, int_type->type_ref, "");
+}
+
static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
AstNode *source_node = instruction->source_node;
Scope *scope = instruction->scope;
@@ -5307,6 +5337,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_mark_err_ret_trace_ptr(g, executable, (IrInstructionMarkErrRetTracePtr *)instruction);
case IrInstructionIdSqrt:
return ir_render_sqrt(g, executable, (IrInstructionSqrt *)instruction);
+ case IrInstructionIdBswap:
+ return ir_render_bswap(g, executable, (IrInstructionBswap *)instruction);
}
zig_unreachable();
}
@@ -6258,8 +6290,14 @@ static void do_code_gen(CodeGen *g) {
}
if (ir_get_var_is_comptime(var))
continue;
- if (type_requires_comptime(var->value->type))
- continue;
+ switch (type_requires_comptime(g, var->value->type)) {
+ case ReqCompTimeInvalid:
+ zig_unreachable();
+ case ReqCompTimeYes:
+ continue;
+ case ReqCompTimeNo:
+ break;
+ }
if (var->src_arg_index == SIZE_MAX) {
var->value_ref = build_alloca(g, var->value->type, buf_ptr(&var->name), var->align_bytes);
@@ -6723,6 +6761,7 @@ static void define_builtin_fns(CodeGen *g) {
create_builtin_fn(g, BuiltinFnIdToBytes, "sliceToBytes", 1);
create_builtin_fn(g, BuiltinFnIdFromBytes, "bytesToSlice", 2);
create_builtin_fn(g, BuiltinFnIdThis, "This", 0);
+ create_builtin_fn(g, BuiltinFnIdBswap, "bswap", 2);
}
static const char *bool_to_str(bool b) {
@@ -8149,7 +8188,11 @@ void codegen_build_and_link(CodeGen *g) {
os_path_join(stage1_dir, buf_create_from_str("build"), manifest_dir);
if ((err = check_cache(g, manifest_dir, &digest))) {
- fprintf(stderr, "Unable to check cache: %s\n", err_str(err));
+ if (err == ErrorCacheUnavailable) {
+ // message already printed
+ } else {
+ fprintf(stderr, "Unable to check cache: %s\n", err_str(err));
+ }
exit(1);
}