authorgravatar for jacoblevgw@gmail.comJacob G-W <jacoblevgw@gmail.com> 2021-08-18 22:22:12-04:00
committergravatar for jacoblevgw@gmail.comJacob G-W <jacoblevgw@gmail.com> 2021-08-19 16:18:40-04:00
log2e6ce11eb29434231102c00fddd0a1b3e0ba5608
treee2cec62c094336d3582cb7b5d5c851dcbb04fe18
parent7e7d67d8eed45bcf3908edd2f4ca864144fffad5

stage2: implement shr and boilerplate for shl

This implements it in the llvm and c backends. x86_64 will have to be a little more work.

10 files changed, 153 insertions(+), 4 deletions(-)

src/Air.zig+8
...@@ -94,6 +94,12 @@ pub const Inst = struct {...@@ -94,6 +94,12 @@ pub const Inst = struct {
94 /// Result type is the same as both operands.94 /// Result type is the same as both operands.
95 /// Uses the `bin_op` field.95 /// Uses the `bin_op` field.
96 bit_or,96 bit_or,
97 /// Shift right. `>>`
98 /// Uses the `bin_op` field.
99 shr,
100 /// Shift left. `<<`
101 /// Uses the `bin_op` field.
102 shl,
97 /// Bitwise XOR. `^`103 /// Bitwise XOR. `^`
98 /// Uses the `bin_op` field.104 /// Uses the `bin_op` field.
99 xor,105 xor,
...@@ -445,6 +451,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -445,6 +451,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
445 .xor,451 .xor,
446 .ptr_add,452 .ptr_add,
447 .ptr_sub,453 .ptr_sub,
454 .shr,
455 .shl,
448 => return air.typeOf(datas[inst].bin_op.lhs),456 => return air.typeOf(datas[inst].bin_op.lhs),
449457
450 .cmp_lt,458 .cmp_lt,
src/Liveness.zig+2
...@@ -249,6 +249,8 @@ fn analyzeInst(...@@ -249,6 +249,8 @@ fn analyzeInst(
249 .ptr_slice_elem_val,249 .ptr_slice_elem_val,
250 .ptr_elem_val,250 .ptr_elem_val,
251 .ptr_ptr_elem_val,251 .ptr_ptr_elem_val,
252 .shl,
253 .shr,
252 => {254 => {
253 const o = inst_datas[inst].bin_op;255 const o = inst_datas[inst].bin_op;
254 return trackOperands(a, new_set, inst, main_tomb, .{ o.lhs, o.rhs, .none });256 return trackOperands(a, new_set, inst, main_tomb, .{ o.lhs, o.rhs, .none });
src/Sema.zig+41-4
...@@ -5303,8 +5303,25 @@ fn zirShr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!A...@@ -5303,8 +5303,25 @@ fn zirShr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!A
5303 const tracy = trace(@src());5303 const tracy = trace(@src());
5304 defer tracy.end();5304 defer tracy.end();
53055305
5306 _ = inst;5306 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
5307 return sema.mod.fail(&block.base, sema.src, "TODO implement zirShr", .{});5307 const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node };
5308 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
5309 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
5310 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
5311 const lhs = sema.resolveInst(extra.lhs);
5312 const rhs = sema.resolveInst(extra.rhs);
5313
5314 if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| {
5315 if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| {
5316 if (lhs_val.isUndef() or rhs_val.isUndef()) {
5317 return sema.addConstUndef(sema.typeOf(lhs));
5318 }
5319 return sema.mod.fail(&block.base, src, "TODO implement comptime shr", .{});
5320 }
5321 }
5322
5323 try sema.requireRuntimeBlock(block, src);
5324 return block.addBinOp(.shr, lhs, rhs);
5308}5325}
53095326
5310fn zirBitwise(5327fn zirBitwise(
...@@ -6001,13 +6018,33 @@ fn zirTypeofElem(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Compile...@@ -6001,13 +6018,33 @@ fn zirTypeofElem(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Compile
6001fn zirTypeofLog2IntType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {6018fn zirTypeofLog2IntType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
6002 const inst_data = sema.code.instructions.items(.data)[inst].un_node;6019 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
6003 const src = inst_data.src();6020 const src = inst_data.src();
6004 return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirTypeofLog2IntType", .{});6021 const operand = sema.resolveInst(inst_data.operand);
6022 const operand_ty = sema.typeOf(operand);
6023 return sema.log2IntType(block, operand_ty, src);
6005}6024}
60066025
6007fn zirLog2IntType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {6026fn zirLog2IntType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
6008 const inst_data = sema.code.instructions.items(.data)[inst].un_node;6027 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
6009 const src = inst_data.src();6028 const src = inst_data.src();
6010 return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirLog2IntType", .{});6029 const operand = try sema.resolveType(block, src, inst_data.operand);
6030 return sema.log2IntType(block, operand, src);
6031}
6032
6033fn log2IntType(sema: *Sema, block: *Scope.Block, operand: Type, src: LazySrcLoc) CompileError!Air.Inst.Ref {
6034 if (operand.zigTypeTag() != .Int) return sema.mod.fail(
6035 &block.base,
6036 src,
6037 "bit shifting operation expected integer type, found '{}'",
6038 .{operand},
6039 );
6040
6041 var count: u16 = 0;
6042 var s = operand.bitSize(sema.mod.getTarget()) - 1;
6043 while (s != 0) : (s >>= 1) {
6044 count += 1;
6045 }
6046 const res = try Module.makeIntType(sema.arena, .unsigned, count);
6047 return sema.addType(res);
6011}6048}
60126049
6013fn zirTypeofPeer(6050fn zirTypeofPeer(
src/codegen.zig+20
...@@ -822,6 +822,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -822,6 +822,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
822 .bit_and => try self.airBitAnd(inst),822 .bit_and => try self.airBitAnd(inst),
823 .bit_or => try self.airBitOr(inst),823 .bit_or => try self.airBitOr(inst),
824 .xor => try self.airXor(inst),824 .xor => try self.airXor(inst),
825 .shr => try self.airShr(inst),
826 .shl => try self.airShl(inst),
825827
826 .alloc => try self.airAlloc(inst),828 .alloc => try self.airAlloc(inst),
827 .arg => try self.airArg(inst),829 .arg => try self.airArg(inst),
...@@ -1270,6 +1272,24 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1270,6 +1272,24 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1270 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1272 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1271 }1273 }
12721274
1275 fn airShl(self: *Self, inst: Air.Inst.Index) !void {
1276 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1277 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {
1278 .arm, .armeb => try self.genArmBinOp(inst, bin_op.lhs, bin_op.rhs, .shl),
1279 else => return self.fail("TODO implement shl for {}", .{self.target.cpu.arch}),
1280 };
1281 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1282 }
1283
1284 fn airShr(self: *Self, inst: Air.Inst.Index) !void {
1285 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1286 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {
1287 .arm, .armeb => try self.genArmBinOp(inst, bin_op.lhs, bin_op.rhs, .shr),
1288 else => return self.fail("TODO implement shr for {}", .{self.target.cpu.arch}),
1289 };
1290 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1291 }
1292
1273 fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void {1293 fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void {
1274 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1294 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1275 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {1295 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {
src/codegen/c.zig+3
...@@ -871,6 +871,9 @@ fn genBody(o: *Object, body: []const Air.Inst.Index) error{ AnalysisFail, OutOfM...@@ -871,6 +871,9 @@ fn genBody(o: *Object, body: []const Air.Inst.Index) error{ AnalysisFail, OutOfM
871 .bit_or => try airBinOp(o, inst, " | "),871 .bit_or => try airBinOp(o, inst, " | "),
872 .xor => try airBinOp(o, inst, " ^ "),872 .xor => try airBinOp(o, inst, " ^ "),
873873
874 .shr => try airBinOp(o, inst, " >> "),
875 .shl => try airBinOp(o, inst, " << "),
876
874 .not => try airNot( o, inst),877 .not => try airNot( o, inst),
875878
876 .optional_payload => try airOptionalPayload(o, inst),879 .optional_payload => try airOptionalPayload(o, inst),
src/codegen/llvm.zig+32
...@@ -993,6 +993,9 @@ pub const FuncGen = struct {...@@ -993,6 +993,9 @@ pub const FuncGen = struct {
993 .bit_or, .bool_or => try self.airOr(inst),993 .bit_or, .bool_or => try self.airOr(inst),
994 .xor => try self.airXor(inst),994 .xor => try self.airXor(inst),
995995
996 .shl => try self.airShl(inst),
997 .shr => try self.airShr(inst),
998
996 .cmp_eq => try self.airCmp(inst, .eq),999 .cmp_eq => try self.airCmp(inst, .eq),
997 .cmp_gt => try self.airCmp(inst, .gt),1000 .cmp_gt => try self.airCmp(inst, .gt),
998 .cmp_gte => try self.airCmp(inst, .gte),1001 .cmp_gte => try self.airCmp(inst, .gte),
...@@ -1736,6 +1739,35 @@ pub const FuncGen = struct {...@@ -1736,6 +1739,35 @@ pub const FuncGen = struct {
1736 return self.builder.buildXor(lhs, rhs, "");1739 return self.builder.buildXor(lhs, rhs, "");
1737 }1740 }
17381741
1742 fn airShl(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
1743 if (self.liveness.isUnused(inst))
1744 return null;
1745 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1746 const lhs = try self.resolveInst(bin_op.lhs);
1747 const rhs = try self.resolveInst(bin_op.rhs);
1748 return self.builder.buildShl(lhs, rhs, "");
1749 }
1750
1751 fn airShr(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
1752 if (self.liveness.isUnused(inst))
1753 return null;
1754 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1755 const lhs = try self.resolveInst(bin_op.lhs);
1756 const rhs = try self.resolveInst(bin_op.rhs);
1757 const lhs_type = self.air.typeOf(bin_op.lhs);
1758 const tg = self.dg.module.getTarget();
1759 const casted_rhs = if (self.air.typeOf(bin_op.rhs).bitSize(tg) < lhs_type.bitSize(tg))
1760 self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_type), "")
1761 else
1762 rhs;
1763
1764 if (self.air.typeOfIndex(inst).isSignedInt()) {
1765 return self.builder.buildAShr(lhs, casted_rhs, "");
1766 } else {
1767 return self.builder.buildLShr(lhs, casted_rhs, "");
1768 }
1769 }
1770
1739 fn airIntCast(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {1771 fn airIntCast(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
1740 if (self.liveness.isUnused(inst))1772 if (self.liveness.isUnused(inst))
1741 return null;1773 return null;
src/codegen/llvm/bindings.zig+17
...@@ -290,6 +290,14 @@ pub const Builder = opaque {...@@ -290,6 +290,14 @@ pub const Builder = opaque {
290 pub const getInsertBlock = LLVMGetInsertBlock;290 pub const getInsertBlock = LLVMGetInsertBlock;
291 extern fn LLVMGetInsertBlock(Builder: *const Builder) *const BasicBlock;291 extern fn LLVMGetInsertBlock(Builder: *const Builder) *const BasicBlock;
292292
293 pub const buildZExt = LLVMBuildZExt;
294 extern fn LLVMBuildZExt(
295 *const Builder,
296 Value: *const Value,
297 DestTy: *const Type,
298 Name: [*:0]const u8,
299 ) *const Value;
300
293 pub const buildCall = LLVMBuildCall;301 pub const buildCall = LLVMBuildCall;
294 extern fn LLVMBuildCall(302 extern fn LLVMBuildCall(
295 *const Builder,303 *const Builder,
...@@ -381,6 +389,15 @@ pub const Builder = opaque {...@@ -381,6 +389,15 @@ pub const Builder = opaque {
381 pub const buildAnd = LLVMBuildAnd;389 pub const buildAnd = LLVMBuildAnd;
382 extern fn LLVMBuildAnd(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;390 extern fn LLVMBuildAnd(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
383391
392 pub const buildLShr = LLVMBuildLShr;
393 extern fn LLVMBuildLShr(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
394
395 pub const buildAShr = LLVMBuildAShr;
396 extern fn LLVMBuildAShr(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
397
398 pub const buildShl = LLVMBuildShl;
399 extern fn LLVMBuildShl(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
400
384 pub const buildOr = LLVMBuildOr;401 pub const buildOr = LLVMBuildOr;
385 extern fn LLVMBuildOr(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;402 extern fn LLVMBuildOr(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
386403
src/print_air.zig+2
...@@ -127,6 +127,8 @@ const Writer = struct {...@@ -127,6 +127,8 @@ const Writer = struct {
127 .ptr_slice_elem_val,127 .ptr_slice_elem_val,
128 .ptr_elem_val,128 .ptr_elem_val,
129 .ptr_ptr_elem_val,129 .ptr_ptr_elem_val,
130 .shl,
131 .shr,
130 => try w.writeBinOp(s, inst),132 => try w.writeBinOp(s, inst),
131133
132 .is_null,134 .is_null,
test/stage2/cbe.zig+14
...@@ -808,6 +808,20 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -808,6 +808,20 @@ pub fn addCases(ctx: *TestContext) !void {
808 });808 });
809 }809 }
810810
811 {
812 var case = ctx.exeUsingLlvmBackend("shift right", linux_x64);
813
814 case.addCompareOutput(
815 \\pub export fn main() void {
816 \\ var i: u32 = 16;
817 \\ assert(i >> 1, 8);
818 \\}
819 \\fn assert(a: u32, b: u32) void {
820 \\ if (a != b) unreachable;
821 \\}
822 , "");
823 }
824
811 {825 {
812 var case = ctx.exeFromCompiledC("inferred error sets", .{});826 var case = ctx.exeFromCompiledC("inferred error sets", .{});
813827
test/stage2/llvm.zig+14
...@@ -28,6 +28,20 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -28,6 +28,20 @@ pub fn addCases(ctx: *TestContext) !void {
28 , "");28 , "");
29 }29 }
3030
31 {
32 var case = ctx.exeUsingLlvmBackend("shift right", linux_x64);
33
34 case.addCompareOutput(
35 \\pub export fn main() void {
36 \\ var i: u32 = 16;
37 \\ assert(i >> 1, 8);
38 \\}
39 \\fn assert(a: u32, b: u32) void {
40 \\ if (a != b) unreachable;
41 \\}
42 , "");
43 }
44
31 {45 {
32 var case = ctx.exeUsingLlvmBackend("llvm hello world", linux_x64);46 var case = ctx.exeUsingLlvmBackend("llvm hello world", linux_x64);
3347