aboutsummaryrefslogtreecommitdiff
path: root/src/codegen.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/codegen.cpp')
-rw-r--r--src/codegen.cpp31
1 files changed, 31 insertions, 0 deletions
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 1033ed8120..08dd11800a 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -3814,6 +3814,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();
}
@@ -5098,6 +5103,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;
@@ -5335,6 +5363,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();
}
@@ -6757,6 +6787,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) {