aboutsummaryrefslogtreecommitdiff
path: root/src/codegen/llvm.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-09-28 22:38:51 -0700
committerAndrew Kelley <andrew@ziglang.org>2021-09-28 22:38:51 -0700
commit33e77f127d8237088b561fae2ca0f4412bc1d6c9 (patch)
tree2ad81a2a7ac5fa5635d6d03456333d30fe568364 /src/codegen/llvm.zig
parent7efc2a06264170632e56256a5fad97e945768056 (diff)
downloadzig-33e77f127d8237088b561fae2ca0f4412bc1d6c9.tar.gz
zig-33e77f127d8237088b561fae2ca0f4412bc1d6c9.zip
stage2: implement `@clz` and `@ctz`
Also improve the LLVM backend to support lowering bigints to LLVM values. Moves over a bunch of math.zig test cases to the "passing for stage2" section.
Diffstat (limited to 'src/codegen/llvm.zig')
-rw-r--r--src/codegen/llvm.zig49
1 files changed, 43 insertions, 6 deletions
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,