aboutsummaryrefslogtreecommitdiff
path: root/src/codegen
diff options
context:
space:
mode:
Diffstat (limited to 'src/codegen')
-rw-r--r--src/codegen/c.zig19
-rw-r--r--src/codegen/llvm.zig49
-rw-r--r--src/codegen/llvm/bindings.zig7
3 files changed, 67 insertions, 8 deletions
diff --git a/src/codegen/c.zig b/src/codegen/c.zig
index 95ce95f2e5..d2ce9cc6de 100644
--- a/src/codegen/c.zig
+++ b/src/codegen/c.zig
@@ -962,6 +962,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
.memcpy => try airMemcpy(f, inst),
.set_union_tag => try airSetUnionTag(f, inst),
.get_union_tag => try airGetUnionTag(f, inst),
+ .clz => try airBuiltinCall(f, inst, "clz"),
+ .ctz => try airBuiltinCall(f, inst, "ctz"),
.int_to_float,
.float_to_int,
@@ -2075,6 +2077,23 @@ fn airSimpleCast(f: *Function, inst: Air.Inst.Index) !CValue {
return local;
}
+fn airBuiltinCall(f: *Function, inst: Air.Inst.Index, fn_name: [*:0]const u8) !CValue {
+ if (f.liveness.isUnused(inst)) return CValue.none;
+
+ const inst_ty = f.air.typeOfIndex(inst);
+ const local = try f.allocLocal(inst_ty, .Const);
+ const ty_op = f.air.instructions.items(.data)[inst].ty_op;
+ const writer = f.object.writer();
+ const operand = try f.resolveInst(ty_op.operand);
+
+ // TODO implement the function in zig.h and call it here
+
+ try writer.print(" = {s}(", .{fn_name});
+ try f.writeCValue(writer, operand);
+ try writer.writeAll(");\n");
+ return local;
+}
+
fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue {
const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
const extra = f.air.extraData(Air.Cmpxchg, ty_pl.payload).data;
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig
index b27afa9b54..2c278221ae 100644
--- a/src/codegen/llvm.zig
+++ b/src/codegen/llvm.zig
@@ -889,14 +889,14 @@ pub const DeclGen = struct {
const llvm_type = try self.llvmType(tv.ty);
if (bigint.eqZero()) return llvm_type.constNull();
- if (bigint.limbs.len != 1) {
- return self.todo("implement bigger bigint", .{});
- }
- const llvm_int = llvm_type.constInt(bigint.limbs[0], .False);
+ const unsigned_val = if (bigint.limbs.len == 1)
+ llvm_type.constInt(bigint.limbs[0], .False)
+ else
+ llvm_type.constIntOfArbitraryPrecision(@intCast(c_uint, bigint.limbs.len), bigint.limbs.ptr);
if (!bigint.positive) {
- return llvm.constNeg(llvm_int);
+ return llvm.constNeg(unsigned_val);
}
- return llvm_int;
+ return unsigned_val;
},
.Enum => {
const llvm_type = try self.llvmType(tv.ty);
@@ -1310,6 +1310,8 @@ pub const FuncGen = struct {
.memcpy => try self.airMemcpy(inst),
.set_union_tag => try self.airSetUnionTag(inst),
.get_union_tag => try self.airGetUnionTag(inst),
+ .clz => try self.airClzCtz(inst, "ctlz"),
+ .ctz => try self.airClzCtz(inst, "cttz"),
.atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
.atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
@@ -2699,6 +2701,41 @@ pub const FuncGen = struct {
return self.builder.buildExtractValue(un, 1, "");
}
+ fn airClzCtz(self: *FuncGen, inst: Air.Inst.Index, prefix: [*:0]const u8) !?*const llvm.Value {
+ if (self.liveness.isUnused(inst)) return null;
+
+ const ty_op = self.air.instructions.items(.data)[inst].ty_op;
+ const operand_ty = self.air.typeOf(ty_op.operand);
+ const operand = try self.resolveInst(ty_op.operand);
+ const target = self.dg.module.getTarget();
+ const bits = operand_ty.intInfo(target).bits;
+
+ var fn_name_buf: [100]u8 = undefined;
+ const llvm_fn_name = std.fmt.bufPrintZ(&fn_name_buf, "llvm.{s}.i{d}", .{
+ prefix, bits,
+ }) catch unreachable;
+ const llvm_i1 = self.context.intType(1);
+ const fn_val = self.dg.object.llvm_module.getNamedFunction(llvm_fn_name) orelse blk: {
+ const operand_llvm_ty = try self.dg.llvmType(operand_ty);
+ const param_types = [_]*const llvm.Type{ operand_llvm_ty, llvm_i1 };
+ const fn_type = llvm.functionType(operand_llvm_ty, &param_types, param_types.len, .False);
+ break :blk self.dg.object.llvm_module.addFunction(llvm_fn_name, fn_type);
+ };
+
+ const params = [_]*const llvm.Value{ operand, llvm_i1.constNull() };
+ const wrong_size_result = self.builder.buildCall(fn_val, &params, params.len, "");
+ const result_ty = self.air.typeOfIndex(inst);
+ const result_llvm_ty = try self.dg.llvmType(result_ty);
+ const result_bits = result_ty.intInfo(target).bits;
+ if (bits > result_bits) {
+ return self.builder.buildTrunc(wrong_size_result, result_llvm_ty, "");
+ } else if (bits < result_bits) {
+ return self.builder.buildZExt(wrong_size_result, result_llvm_ty, "");
+ } else {
+ return wrong_size_result;
+ }
+ }
+
fn fieldPtr(
self: *FuncGen,
inst: Air.Inst.Index,
diff --git a/src/codegen/llvm/bindings.zig b/src/codegen/llvm/bindings.zig
index 4fac6656c8..68d91f6c68 100644
--- a/src/codegen/llvm/bindings.zig
+++ b/src/codegen/llvm/bindings.zig
@@ -172,6 +172,9 @@ pub const Type = opaque {
pub const constInt = LLVMConstInt;
extern fn LLVMConstInt(IntTy: *const Type, N: c_ulonglong, SignExtend: Bool) *const Value;
+ pub const constIntOfArbitraryPrecision = LLVMConstIntOfArbitraryPrecision;
+ extern fn LLVMConstIntOfArbitraryPrecision(IntTy: *const Type, NumWords: c_uint, Words: [*]const u64) *const Value;
+
pub const constReal = LLVMConstReal;
extern fn LLVMConstReal(RealTy: *const Type, N: f64) *const Value;
@@ -300,7 +303,7 @@ extern fn LLVMGetInlineAsm(
pub const functionType = LLVMFunctionType;
extern fn LLVMFunctionType(
ReturnType: *const Type,
- ParamTypes: [*]*const Type,
+ ParamTypes: [*]const *const Type,
ParamCount: c_uint,
IsVarArg: Bool,
) *const Type;
@@ -346,7 +349,7 @@ pub const Builder = opaque {
extern fn LLVMBuildCall(
*const Builder,
Fn: *const Value,
- Args: [*]*const Value,
+ Args: [*]const *const Value,
NumArgs: c_uint,
Name: [*:0]const u8,
) *const Value;