Commit 2e6ce11eb2
Changed files (10)
src/codegen/llvm/bindings.zig
@@ -290,6 +290,14 @@ pub const Builder = opaque {
pub const getInsertBlock = LLVMGetInsertBlock;
extern fn LLVMGetInsertBlock(Builder: *const Builder) *const BasicBlock;
+ pub const buildZExt = LLVMBuildZExt;
+ extern fn LLVMBuildZExt(
+ *const Builder,
+ Value: *const Value,
+ DestTy: *const Type,
+ Name: [*:0]const u8,
+ ) *const Value;
+
pub const buildCall = LLVMBuildCall;
extern fn LLVMBuildCall(
*const Builder,
@@ -381,6 +389,15 @@ pub const Builder = opaque {
pub const buildAnd = LLVMBuildAnd;
extern fn LLVMBuildAnd(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
+ pub const buildLShr = LLVMBuildLShr;
+ extern fn LLVMBuildLShr(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
+
+ pub const buildAShr = LLVMBuildAShr;
+ extern fn LLVMBuildAShr(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
+
+ pub const buildShl = LLVMBuildShl;
+ extern fn LLVMBuildShl(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
+
pub const buildOr = LLVMBuildOr;
extern fn LLVMBuildOr(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
src/codegen/c.zig
@@ -871,6 +871,9 @@ fn genBody(o: *Object, body: []const Air.Inst.Index) error{ AnalysisFail, OutOfM
.bit_or => try airBinOp(o, inst, " | "),
.xor => try airBinOp(o, inst, " ^ "),
+ .shr => try airBinOp(o, inst, " >> "),
+ .shl => try airBinOp(o, inst, " << "),
+
.not => try airNot( o, inst),
.optional_payload => try airOptionalPayload(o, inst),
src/codegen/llvm.zig
@@ -993,6 +993,9 @@ pub const FuncGen = struct {
.bit_or, .bool_or => try self.airOr(inst),
.xor => try self.airXor(inst),
+ .shl => try self.airShl(inst),
+ .shr => try self.airShr(inst),
+
.cmp_eq => try self.airCmp(inst, .eq),
.cmp_gt => try self.airCmp(inst, .gt),
.cmp_gte => try self.airCmp(inst, .gte),
@@ -1736,6 +1739,35 @@ pub const FuncGen = struct {
return self.builder.buildXor(lhs, rhs, "");
}
+ fn airShl(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
+ if (self.liveness.isUnused(inst))
+ return null;
+ const bin_op = self.air.instructions.items(.data)[inst].bin_op;
+ const lhs = try self.resolveInst(bin_op.lhs);
+ const rhs = try self.resolveInst(bin_op.rhs);
+ return self.builder.buildShl(lhs, rhs, "");
+ }
+
+ fn airShr(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
+ if (self.liveness.isUnused(inst))
+ return null;
+ const bin_op = self.air.instructions.items(.data)[inst].bin_op;
+ const lhs = try self.resolveInst(bin_op.lhs);
+ const rhs = try self.resolveInst(bin_op.rhs);
+ const lhs_type = self.air.typeOf(bin_op.lhs);
+ const tg = self.dg.module.getTarget();
+ const casted_rhs = if (self.air.typeOf(bin_op.rhs).bitSize(tg) < lhs_type.bitSize(tg))
+ self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_type), "")
+ else
+ rhs;
+
+ if (self.air.typeOfIndex(inst).isSignedInt()) {
+ return self.builder.buildAShr(lhs, casted_rhs, "");
+ } else {
+ return self.builder.buildLShr(lhs, casted_rhs, "");
+ }
+ }
+
fn airIntCast(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
if (self.liveness.isUnused(inst))
return null;
src/Air.zig
@@ -94,6 +94,12 @@ pub const Inst = struct {
/// Result type is the same as both operands.
/// Uses the `bin_op` field.
bit_or,
+ /// Shift right. `>>`
+ /// Uses the `bin_op` field.
+ shr,
+ /// Shift left. `<<`
+ /// Uses the `bin_op` field.
+ shl,
/// Bitwise XOR. `^`
/// Uses the `bin_op` field.
xor,
@@ -445,6 +451,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
.xor,
.ptr_add,
.ptr_sub,
+ .shr,
+ .shl,
=> return air.typeOf(datas[inst].bin_op.lhs),
.cmp_lt,
src/codegen.zig
@@ -822,6 +822,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
.bit_and => try self.airBitAnd(inst),
.bit_or => try self.airBitOr(inst),
.xor => try self.airXor(inst),
+ .shr => try self.airShr(inst),
+ .shl => try self.airShl(inst),
.alloc => try self.airAlloc(inst),
.arg => try self.airArg(inst),
@@ -1270,6 +1272,24 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
}
+ fn airShl(self: *Self, inst: Air.Inst.Index) !void {
+ const bin_op = self.air.instructions.items(.data)[inst].bin_op;
+ const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {
+ .arm, .armeb => try self.genArmBinOp(inst, bin_op.lhs, bin_op.rhs, .shl),
+ else => return self.fail("TODO implement shl for {}", .{self.target.cpu.arch}),
+ };
+ return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
+ }
+
+ fn airShr(self: *Self, inst: Air.Inst.Index) !void {
+ const bin_op = self.air.instructions.items(.data)[inst].bin_op;
+ const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {
+ .arm, .armeb => try self.genArmBinOp(inst, bin_op.lhs, bin_op.rhs, .shr),
+ else => return self.fail("TODO implement shr for {}", .{self.target.cpu.arch}),
+ };
+ return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
+ }
+
fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void {
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {
src/Liveness.zig
@@ -249,6 +249,8 @@ fn analyzeInst(
.ptr_slice_elem_val,
.ptr_elem_val,
.ptr_ptr_elem_val,
+ .shl,
+ .shr,
=> {
const o = inst_datas[inst].bin_op;
return trackOperands(a, new_set, inst, main_tomb, .{ o.lhs, o.rhs, .none });
src/print_air.zig
@@ -127,6 +127,8 @@ const Writer = struct {
.ptr_slice_elem_val,
.ptr_elem_val,
.ptr_ptr_elem_val,
+ .shl,
+ .shr,
=> try w.writeBinOp(s, inst),
.is_null,
src/Sema.zig
@@ -5303,8 +5303,25 @@ fn zirShr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!A
const tracy = trace(@src());
defer tracy.end();
- _ = inst;
- return sema.mod.fail(&block.base, sema.src, "TODO implement zirShr", .{});
+ const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
+ const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node };
+ const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
+ const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
+ const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
+ const lhs = sema.resolveInst(extra.lhs);
+ const rhs = sema.resolveInst(extra.rhs);
+
+ if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| {
+ if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| {
+ if (lhs_val.isUndef() or rhs_val.isUndef()) {
+ return sema.addConstUndef(sema.typeOf(lhs));
+ }
+ return sema.mod.fail(&block.base, src, "TODO implement comptime shr", .{});
+ }
+ }
+
+ try sema.requireRuntimeBlock(block, src);
+ return block.addBinOp(.shr, lhs, rhs);
}
fn zirBitwise(
@@ -6001,13 +6018,33 @@ fn zirTypeofElem(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Compile
fn zirTypeofLog2IntType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const src = inst_data.src();
- return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirTypeofLog2IntType", .{});
+ const operand = sema.resolveInst(inst_data.operand);
+ const operand_ty = sema.typeOf(operand);
+ return sema.log2IntType(block, operand_ty, src);
}
fn zirLog2IntType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const src = inst_data.src();
- return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirLog2IntType", .{});
+ const operand = try sema.resolveType(block, src, inst_data.operand);
+ return sema.log2IntType(block, operand, src);
+}
+
+fn log2IntType(sema: *Sema, block: *Scope.Block, operand: Type, src: LazySrcLoc) CompileError!Air.Inst.Ref {
+ if (operand.zigTypeTag() != .Int) return sema.mod.fail(
+ &block.base,
+ src,
+ "bit shifting operation expected integer type, found '{}'",
+ .{operand},
+ );
+
+ var count: u16 = 0;
+ var s = operand.bitSize(sema.mod.getTarget()) - 1;
+ while (s != 0) : (s >>= 1) {
+ count += 1;
+ }
+ const res = try Module.makeIntType(sema.arena, .unsigned, count);
+ return sema.addType(res);
}
fn zirTypeofPeer(
test/stage2/cbe.zig
@@ -808,6 +808,20 @@ pub fn addCases(ctx: *TestContext) !void {
});
}
+ {
+ var case = ctx.exeUsingLlvmBackend("shift right", linux_x64);
+
+ case.addCompareOutput(
+ \\pub export fn main() void {
+ \\ var i: u32 = 16;
+ \\ assert(i >> 1, 8);
+ \\}
+ \\fn assert(a: u32, b: u32) void {
+ \\ if (a != b) unreachable;
+ \\}
+ , "");
+ }
+
{
var case = ctx.exeFromCompiledC("inferred error sets", .{});
test/stage2/llvm.zig
@@ -28,6 +28,20 @@ pub fn addCases(ctx: *TestContext) !void {
, "");
}
+ {
+ var case = ctx.exeUsingLlvmBackend("shift right", linux_x64);
+
+ case.addCompareOutput(
+ \\pub export fn main() void {
+ \\ var i: u32 = 16;
+ \\ assert(i >> 1, 8);
+ \\}
+ \\fn assert(a: u32, b: u32) void {
+ \\ if (a != b) unreachable;
+ \\}
+ , "");
+ }
+
{
var case = ctx.exeUsingLlvmBackend("llvm hello world", linux_x64);