From 82236a502959d39b97c783dc409a9a5b720e6e8b Mon Sep 17 00:00:00 2001 From: joachimschmidt557 Date: Sun, 20 Dec 2020 14:50:48 +0100 Subject: [PATCH] stage2 ARM: implement basic binary bitwise operations --- src/codegen.zig | 39 +++++++++++++++++++++++++++--- src/ir.zig | 6 +++++ src/zir.zig | 3 +++ src/zir_sema.zig | 63 ++++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 106 insertions(+), 5 deletions(-) diff --git a/src/codegen.zig b/src/codegen.zig index 3b0a383a71..01deb13c0e 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -764,6 +764,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { .arg => return self.genArg(inst.castTag(.arg).?), .assembly => return self.genAsm(inst.castTag(.assembly).?), .bitcast => return self.genBitCast(inst.castTag(.bitcast).?), + .bitand => return self.genBitAnd(inst.castTag(.bitand).?), + .bitor => return self.genBitOr(inst.castTag(.bitor).?), .block => return self.genBlock(inst.castTag(.block).?), .br => return self.genBr(inst.castTag(.br).?), .breakpoint => return self.genBreakpoint(inst.src), @@ -799,6 +801,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { .unwrap_optional => return self.genUnwrapOptional(inst.castTag(.unwrap_optional).?), .wrap_optional => return self.genWrapOptional(inst.castTag(.wrap_optional).?), .varptr => return self.genVarPtr(inst.castTag(.varptr).?), + .xor => return self.genXor(inst.castTag(.xor).?), } } @@ -1009,6 +1012,36 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { } } + fn genBitAnd(self: *Self, inst: *ir.Inst.BinOp) !MCValue { + // No side effects, so if it's unreferenced, do nothing. + if (inst.base.isUnused()) + return MCValue.dead; + switch (arch) { + .arm, .armeb => return try self.genArmBinOp(&inst.base, inst.lhs, inst.rhs, .bitand), + else => return self.fail(inst.base.src, "TODO implement bitwise and for {}", .{self.target.cpu.arch}), + } + } + + fn genBitOr(self: *Self, inst: *ir.Inst.BinOp) !MCValue { + // No side effects, so if it's unreferenced, do nothing. + if (inst.base.isUnused()) + return MCValue.dead; + switch (arch) { + .arm, .armeb => return try self.genArmBinOp(&inst.base, inst.lhs, inst.rhs, .bitor), + else => return self.fail(inst.base.src, "TODO implement bitwise or for {}", .{self.target.cpu.arch}), + } + } + + fn genXor(self: *Self, inst: *ir.Inst.BinOp) !MCValue { + // No side effects, so if it's unreferenced, do nothing. + if (inst.base.isUnused()) + return MCValue.dead; + switch (arch) { + .arm, .armeb => return try self.genArmBinOp(&inst.base, inst.lhs, inst.rhs, .xor), + else => return self.fail(inst.base.src, "TODO implement xor for {}", .{self.target.cpu.arch}), + } + } + fn genUnwrapOptional(self: *Self, inst: *ir.Inst.UnOp) !MCValue { // No side effects, so if it's unreferenced, do nothing. if (inst.base.isUnused()) @@ -1251,13 +1284,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { writeInt(u32, try self.code.addManyAsArray(4), Instruction.rsb(.al, dst_reg, dst_reg, operand).toU32()); } }, - .booland => { + .booland, .bitand => { writeInt(u32, try self.code.addManyAsArray(4), Instruction.@"and"(.al, dst_reg, dst_reg, operand).toU32()); }, - .boolor => { + .boolor, .bitor => { writeInt(u32, try self.code.addManyAsArray(4), Instruction.orr(.al, dst_reg, dst_reg, operand).toU32()); }, - .not => { + .not, .xor => { writeInt(u32, try self.code.addManyAsArray(4), Instruction.eor(.al, dst_reg, dst_reg, operand).toU32()); }, else => unreachable, // not a binary instruction diff --git a/src/ir.zig b/src/ir.zig index 1a31044ab7..fc29323247 100644 --- a/src/ir.zig +++ b/src/ir.zig @@ -56,7 +56,9 @@ pub const Inst = struct { alloc, arg, assembly, + bitand, bitcast, + bitor, block, br, breakpoint, @@ -93,6 +95,7 @@ pub const Inst = struct { intcast, unwrap_optional, wrap_optional, + xor, switchbr, pub fn Type(tag: Tag) type { @@ -130,6 +133,9 @@ pub const Inst = struct { .store, .booland, .boolor, + .bitand, + .bitor, + .xor, => BinOp, .arg => Arg, diff --git a/src/zir.zig b/src/zir.zig index 6a59ac4994..f23dccac57 100644 --- a/src/zir.zig +++ b/src/zir.zig @@ -2330,6 +2330,9 @@ const EmitZIR = struct { .cmp_neq => try self.emitBinOp(inst.src, new_body, inst.castTag(.cmp_neq).?, .cmp_neq), .booland => try self.emitBinOp(inst.src, new_body, inst.castTag(.booland).?, .booland), .boolor => try self.emitBinOp(inst.src, new_body, inst.castTag(.boolor).?, .boolor), + .bitand => try self.emitBinOp(inst.src, new_body, inst.castTag(.bitand).?, .bitand), + .bitor => try self.emitBinOp(inst.src, new_body, inst.castTag(.bitor).?, .bitor), + .xor => try self.emitBinOp(inst.src, new_body, inst.castTag(.xor).?, .xor), .bitcast => try self.emitCast(inst.src, new_body, inst.castTag(.bitcast).?, .bitcast), .intcast => try self.emitCast(inst.src, new_body, inst.castTag(.intcast).?, .intcast), diff --git a/src/zir_sema.zig b/src/zir_sema.zig index 602da97f81..e7b191f8fe 100644 --- a/src/zir_sema.zig +++ b/src/zir_sema.zig @@ -1458,7 +1458,66 @@ fn analyzeInstShr(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError } fn analyzeInstBitwise(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { - return mod.fail(scope, inst.base.src, "TODO implement analyzeInstBitwise", .{}); + const tracy = trace(@src()); + defer tracy.end(); + + const lhs = try resolveInst(mod, scope, inst.positionals.lhs); + const rhs = try resolveInst(mod, scope, inst.positionals.rhs); + + const instructions = &[_]*Inst{ lhs, rhs }; + const resolved_type = try mod.resolvePeerTypes(scope, instructions); + const casted_lhs = try mod.coerce(scope, resolved_type, lhs); + const casted_rhs = try mod.coerce(scope, resolved_type, rhs); + + const scalar_type = if (resolved_type.zigTypeTag() == .Vector) + resolved_type.elemType() + else + resolved_type; + + const scalar_tag = scalar_type.zigTypeTag(); + + if (lhs.ty.zigTypeTag() == .Vector and rhs.ty.zigTypeTag() == .Vector) { + if (lhs.ty.arrayLen() != rhs.ty.arrayLen()) { + return mod.fail(scope, inst.base.src, "vector length mismatch: {} and {}", .{ + lhs.ty.arrayLen(), + rhs.ty.arrayLen(), + }); + } + return mod.fail(scope, inst.base.src, "TODO implement support for vectors in analyzeInstBitwise", .{}); + } else if (lhs.ty.zigTypeTag() == .Vector or rhs.ty.zigTypeTag() == .Vector) { + return mod.fail(scope, inst.base.src, "mixed scalar and vector operands to binary expression: '{}' and '{}'", .{ + lhs.ty, + rhs.ty, + }); + } + + const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; + + if (!is_int) { + return mod.fail(scope, inst.base.src, "invalid operands to binary bitwise expression: '{}' and '{}'", .{ @tagName(lhs.ty.zigTypeTag()), @tagName(rhs.ty.zigTypeTag()) }); + } + + if (casted_lhs.value()) |lhs_val| { + if (casted_rhs.value()) |rhs_val| { + if (lhs_val.isUndef() or rhs_val.isUndef()) { + return mod.constInst(scope, inst.base.src, .{ + .ty = resolved_type, + .val = Value.initTag(.undef), + }); + } + return mod.fail(scope, inst.base.src, "TODO implement comptime bitwise operations", .{}); + } + } + + const b = try mod.requireRuntimeBlock(scope, inst.base.src); + const ir_tag = switch (inst.base.tag) { + .bitand => Inst.Tag.bitand, + .bitor => Inst.Tag.bitor, + .xor => Inst.Tag.xor, + else => unreachable, + }; + + return mod.addBinOp(b, inst.base.src, scalar_type, ir_tag, casted_lhs, casted_rhs); } fn analyzeInstBitNot(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { @@ -1501,7 +1560,7 @@ fn analyzeInstArithmetic(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) Inn } return mod.fail(scope, inst.base.src, "TODO implement support for vectors in analyzeInstBinOp", .{}); } else if (lhs.ty.zigTypeTag() == .Vector or rhs.ty.zigTypeTag() == .Vector) { - return mod.fail(scope, inst.base.src, "mixed scalar and vector operands to comparison operator: '{}' and '{}'", .{ + return mod.fail(scope, inst.base.src, "mixed scalar and vector operands to binary expression: '{}' and '{}'", .{ lhs.ty, rhs.ty, });