aboutsummaryrefslogtreecommitdiff
path: root/src/codegen.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/codegen.cpp')
-rw-r--r--src/codegen.cpp41
1 files changed, 39 insertions, 2 deletions
diff --git a/src/codegen.cpp b/src/codegen.cpp
index bf208a527b..7cfd699ce4 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -227,6 +227,24 @@ static LLVMValueRef get_int_overflow_fn(CodeGen *g, TypeTableEntry *type_entry,
return *fn;
}
+static LLVMValueRef get_int_builtin_fn(CodeGen *g, TypeTableEntry *int_type, BuiltinFnId fn_id) {
+ // [0-ctz,1-clz][0-8,1-16,2-32,3-64]
+ int index0 = (fn_id == BuiltinFnIdCtz) ? 0 : 1;
+ int index1 = bits_index(int_type->data.integral.bit_count);
+ LLVMValueRef *fn = &g->int_builtin_fns[index0][index1];
+ if (!*fn) {
+ const char *fn_name = (fn_id == BuiltinFnIdCtz) ? "cttz" : "ctlz";
+ Buf *llvm_name = buf_sprintf("llvm.%s.i%d", fn_name, int_type->data.integral.bit_count);
+ LLVMTypeRef param_types[] = {
+ int_type->type_ref,
+ LLVMInt1Type(),
+ };
+ LLVMTypeRef fn_type = LLVMFunctionType(int_type->type_ref, param_types, 2, false);
+ *fn = LLVMAddFunction(g->module, buf_ptr(llvm_name), fn_type);
+ }
+ return *fn;
+}
+
static LLVMValueRef get_handle_value(CodeGen *g, AstNode *source_node, LLVMValueRef ptr, TypeTableEntry *type) {
if (handle_is_ptr(type)) {
return ptr;
@@ -249,6 +267,22 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {
case BuiltinFnIdCDefine:
case BuiltinFnIdCUndef:
zig_unreachable();
+ case BuiltinFnIdCtz:
+ case BuiltinFnIdClz:
+ {
+ int fn_call_param_count = node->data.fn_call_expr.params.length;
+ assert(fn_call_param_count == 2);
+ TypeTableEntry *int_type = get_type_for_type_node(node->data.fn_call_expr.params.at(0));
+ assert(int_type->id == TypeTableEntryIdInt);
+ LLVMValueRef fn_val = get_int_builtin_fn(g, int_type, builtin_fn->id);
+ LLVMValueRef operand = gen_expr(g, node->data.fn_call_expr.params.at(1));
+ LLVMValueRef params[] {
+ operand,
+ LLVMConstNull(LLVMInt1Type()),
+ };
+ add_debug_source_node(g, node);
+ return LLVMBuildCall(g->builder, fn_val, params, 2, "");
+ }
case BuiltinFnIdAddWithOverflow:
case BuiltinFnIdSubWithOverflow:
case BuiltinFnIdMulWithOverflow:
@@ -1025,11 +1059,12 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) {
case PrefixOpDereference:
{
LLVMValueRef expr = gen_expr(g, expr_node);
+ assert(expr_type->id == TypeTableEntryIdPointer);
if (!type_has_bits(expr_type)) {
return nullptr;
} else {
- add_debug_source_node(g, node);
- return LLVMBuildLoad(g->builder, expr, "");
+ TypeTableEntry *child_type = expr_type->data.pointer.child_type;
+ return get_handle_value(g, node, expr, child_type);
}
}
case PrefixOpMaybe:
@@ -3590,6 +3625,8 @@ static void define_builtin_fns(CodeGen *g) {
create_builtin_fn_with_arg_count(g, BuiltinFnIdCUndef, "c_undef", 1);
create_builtin_fn_with_arg_count(g, BuiltinFnIdCompileVar, "compile_var", 1);
create_builtin_fn_with_arg_count(g, BuiltinFnIdConstEval, "const_eval", 1);
+ create_builtin_fn_with_arg_count(g, BuiltinFnIdCtz, "ctz", 2);
+ create_builtin_fn_with_arg_count(g, BuiltinFnIdClz, "clz", 2);
}
static void init(CodeGen *g, Buf *source_path) {