aboutsummaryrefslogtreecommitdiff
path: root/src/codegen.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/codegen.cpp')
-rw-r--r--src/codegen.cpp48
1 files changed, 46 insertions, 2 deletions
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 661bf8183f..aa4588dd47 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -1478,6 +1478,46 @@ static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable,
}
}
+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]
+ size_t index0 = (fn_id == BuiltinFnIdCtz) ? 0 : 1;
+ size_t 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%zu", 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 ir_render_clz(CodeGen *g, IrExecutable *executable, IrInstructionClz *instruction) {
+ TypeTableEntry *int_type = instruction->base.type_entry;
+ LLVMValueRef fn_val = get_int_builtin_fn(g, int_type, BuiltinFnIdClz);
+ LLVMValueRef operand = ir_llvm_value(g, instruction->value);
+ LLVMValueRef params[] {
+ operand,
+ LLVMConstNull(LLVMInt1Type()),
+ };
+ return LLVMBuildCall(g->builder, fn_val, params, 2, "");
+}
+
+static LLVMValueRef ir_render_ctz(CodeGen *g, IrExecutable *executable, IrInstructionCtz *instruction) {
+ TypeTableEntry *int_type = instruction->base.type_entry;
+ LLVMValueRef fn_val = get_int_builtin_fn(g, int_type, BuiltinFnIdCtz);
+ LLVMValueRef operand = ir_llvm_value(g, instruction->value);
+ LLVMValueRef params[] {
+ operand,
+ LLVMConstNull(LLVMInt1Type()),
+ };
+ return LLVMBuildCall(g->builder, fn_val, params, 2, "");
+}
+
static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, IrInstruction *instruction) {
set_debug_source_node(g, instruction->source_node);
@@ -1529,6 +1569,10 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_test_null(g, executable, (IrInstructionTestNull *)instruction);
case IrInstructionIdUnwrapMaybe:
return ir_render_unwrap_maybe(g, executable, (IrInstructionUnwrapMaybe *)instruction);
+ case IrInstructionIdClz:
+ return ir_render_clz(g, executable, (IrInstructionClz *)instruction);
+ case IrInstructionIdCtz:
+ return ir_render_ctz(g, executable, (IrInstructionCtz *)instruction);
case IrInstructionIdSwitchBr:
case IrInstructionIdPhi:
case IrInstructionIdContainerInitList:
@@ -2774,8 +2818,8 @@ static void define_builtin_fns(CodeGen *g) {
create_builtin_fn_with_arg_count(g, BuiltinFnIdCUndef, "cUndef", 1);
create_builtin_fn_with_arg_count(g, BuiltinFnIdCompileVar, "compileVar", 1);
create_builtin_fn_with_arg_count(g, BuiltinFnIdConstEval, "constEval", 1);
- create_builtin_fn_with_arg_count(g, BuiltinFnIdCtz, "ctz", 2);
- create_builtin_fn_with_arg_count(g, BuiltinFnIdClz, "clz", 2);
+ create_builtin_fn_with_arg_count(g, BuiltinFnIdCtz, "ctz", 1);
+ create_builtin_fn_with_arg_count(g, BuiltinFnIdClz, "clz", 1);
create_builtin_fn_with_arg_count(g, BuiltinFnIdImport, "import", 1);
create_builtin_fn_with_arg_count(g, BuiltinFnIdCImport, "cImport", 1);
create_builtin_fn_with_arg_count(g, BuiltinFnIdErrName, "errorName", 1);