| author | |
| committer | |
| log | 82236a502959d39b97c783dc409a9a5b720e6e8b |
| tree | a6f741bab53ea91bafe9403afc815cc33c1ad92c |
| parent | 286077fec8f381c7b4d4d5bf351d963564a1dd69 |
| signature |
4 files changed, 106 insertions(+), 5 deletions(-)
src/codegen.zig+36-3| ... | @@ -764,6 +764,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -764,6 +764,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 764 | .arg => return self.genArg(inst.castTag(.arg).?), | 764 | .arg => return self.genArg(inst.castTag(.arg).?), |
| 765 | .assembly => return self.genAsm(inst.castTag(.assembly).?), | 765 | .assembly => return self.genAsm(inst.castTag(.assembly).?), |
| 766 | .bitcast => return self.genBitCast(inst.castTag(.bitcast).?), | 766 | .bitcast => return self.genBitCast(inst.castTag(.bitcast).?), |
| 767 | .bitand => return self.genBitAnd(inst.castTag(.bitand).?), | ||
| 768 | .bitor => return self.genBitOr(inst.castTag(.bitor).?), | ||
| 767 | .block => return self.genBlock(inst.castTag(.block).?), | 769 | .block => return self.genBlock(inst.castTag(.block).?), |
| 768 | .br => return self.genBr(inst.castTag(.br).?), | 770 | .br => return self.genBr(inst.castTag(.br).?), |
| 769 | .breakpoint => return self.genBreakpoint(inst.src), | 771 | .breakpoint => return self.genBreakpoint(inst.src), |
| ... | @@ -799,6 +801,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -799,6 +801,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 799 | .unwrap_optional => return self.genUnwrapOptional(inst.castTag(.unwrap_optional).?), | 801 | .unwrap_optional => return self.genUnwrapOptional(inst.castTag(.unwrap_optional).?), |
| 800 | .wrap_optional => return self.genWrapOptional(inst.castTag(.wrap_optional).?), | 802 | .wrap_optional => return self.genWrapOptional(inst.castTag(.wrap_optional).?), |
| 801 | .varptr => return self.genVarPtr(inst.castTag(.varptr).?), | 803 | .varptr => return self.genVarPtr(inst.castTag(.varptr).?), |
| 804 | .xor => return self.genXor(inst.castTag(.xor).?), | ||
| 802 | } | 805 | } |
| 803 | } | 806 | } |
| 804 | 807 | ||
| ... | @@ -1009,6 +1012,36 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1009,6 +1012,36 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1009 | } | 1012 | } |
| 1010 | } | 1013 | } |
| 1011 | 1014 | ||
| 1015 | fn genBitAnd(self: *Self, inst: *ir.Inst.BinOp) !MCValue { | ||
| 1016 | // No side effects, so if it's unreferenced, do nothing. | ||
| 1017 | if (inst.base.isUnused()) | ||
| 1018 | return MCValue.dead; | ||
| 1019 | switch (arch) { | ||
| 1020 | .arm, .armeb => return try self.genArmBinOp(&inst.base, inst.lhs, inst.rhs, .bitand), | ||
| 1021 | else => return self.fail(inst.base.src, "TODO implement bitwise and for {}", .{self.target.cpu.arch}), | ||
| 1022 | } | ||
| 1023 | } | ||
| 1024 | |||
| 1025 | fn genBitOr(self: *Self, inst: *ir.Inst.BinOp) !MCValue { | ||
| 1026 | // No side effects, so if it's unreferenced, do nothing. | ||
| 1027 | if (inst.base.isUnused()) | ||
| 1028 | return MCValue.dead; | ||
| 1029 | switch (arch) { | ||
| 1030 | .arm, .armeb => return try self.genArmBinOp(&inst.base, inst.lhs, inst.rhs, .bitor), | ||
| 1031 | else => return self.fail(inst.base.src, "TODO implement bitwise or for {}", .{self.target.cpu.arch}), | ||
| 1032 | } | ||
| 1033 | } | ||
| 1034 | |||
| 1035 | fn genXor(self: *Self, inst: *ir.Inst.BinOp) !MCValue { | ||
| 1036 | // No side effects, so if it's unreferenced, do nothing. | ||
| 1037 | if (inst.base.isUnused()) | ||
| 1038 | return MCValue.dead; | ||
| 1039 | switch (arch) { | ||
| 1040 | .arm, .armeb => return try self.genArmBinOp(&inst.base, inst.lhs, inst.rhs, .xor), | ||
| 1041 | else => return self.fail(inst.base.src, "TODO implement xor for {}", .{self.target.cpu.arch}), | ||
| 1042 | } | ||
| 1043 | } | ||
| 1044 | |||
| 1012 | fn genUnwrapOptional(self: *Self, inst: *ir.Inst.UnOp) !MCValue { | 1045 | fn genUnwrapOptional(self: *Self, inst: *ir.Inst.UnOp) !MCValue { |
| 1013 | // No side effects, so if it's unreferenced, do nothing. | 1046 | // No side effects, so if it's unreferenced, do nothing. |
| 1014 | if (inst.base.isUnused()) | 1047 | if (inst.base.isUnused()) |
| ... | @@ -1251,13 +1284,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1251,13 +1284,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1251 | writeInt(u32, try self.code.addManyAsArray(4), Instruction.rsb(.al, dst_reg, dst_reg, operand).toU32()); | 1284 | writeInt(u32, try self.code.addManyAsArray(4), Instruction.rsb(.al, dst_reg, dst_reg, operand).toU32()); |
| 1252 | } | 1285 | } |
| 1253 | }, | 1286 | }, |
| 1254 | .booland => { | 1287 | .booland, .bitand => { |
| 1255 | writeInt(u32, try self.code.addManyAsArray(4), Instruction.@"and"(.al, dst_reg, dst_reg, operand).toU32()); | 1288 | writeInt(u32, try self.code.addManyAsArray(4), Instruction.@"and"(.al, dst_reg, dst_reg, operand).toU32()); |
| 1256 | }, | 1289 | }, |
| 1257 | .boolor => { | 1290 | .boolor, .bitor => { |
| 1258 | writeInt(u32, try self.code.addManyAsArray(4), Instruction.orr(.al, dst_reg, dst_reg, operand).toU32()); | 1291 | writeInt(u32, try self.code.addManyAsArray(4), Instruction.orr(.al, dst_reg, dst_reg, operand).toU32()); |
| 1259 | }, | 1292 | }, |
| 1260 | .not => { | 1293 | .not, .xor => { |
| 1261 | writeInt(u32, try self.code.addManyAsArray(4), Instruction.eor(.al, dst_reg, dst_reg, operand).toU32()); | 1294 | writeInt(u32, try self.code.addManyAsArray(4), Instruction.eor(.al, dst_reg, dst_reg, operand).toU32()); |
| 1262 | }, | 1295 | }, |
| 1263 | else => unreachable, // not a binary instruction | 1296 | else => unreachable, // not a binary instruction |
src/ir.zig+6| ... | @@ -56,7 +56,9 @@ pub const Inst = struct { | ... | @@ -56,7 +56,9 @@ pub const Inst = struct { |
| 56 | alloc, | 56 | alloc, |
| 57 | arg, | 57 | arg, |
| 58 | assembly, | 58 | assembly, |
| 59 | bitand, | ||
| 59 | bitcast, | 60 | bitcast, |
| 61 | bitor, | ||
| 60 | block, | 62 | block, |
| 61 | br, | 63 | br, |
| 62 | breakpoint, | 64 | breakpoint, |
| ... | @@ -93,6 +95,7 @@ pub const Inst = struct { | ... | @@ -93,6 +95,7 @@ pub const Inst = struct { |
| 93 | intcast, | 95 | intcast, |
| 94 | unwrap_optional, | 96 | unwrap_optional, |
| 95 | wrap_optional, | 97 | wrap_optional, |
| 98 | xor, | ||
| 96 | switchbr, | 99 | switchbr, |
| 97 | 100 | ||
| 98 | pub fn Type(tag: Tag) type { | 101 | pub fn Type(tag: Tag) type { |
| ... | @@ -130,6 +133,9 @@ pub const Inst = struct { | ... | @@ -130,6 +133,9 @@ pub const Inst = struct { |
| 130 | .store, | 133 | .store, |
| 131 | .booland, | 134 | .booland, |
| 132 | .boolor, | 135 | .boolor, |
| 136 | .bitand, | ||
| 137 | .bitor, | ||
| 138 | .xor, | ||
| 133 | => BinOp, | 139 | => BinOp, |
| 134 | 140 | ||
| 135 | .arg => Arg, | 141 | .arg => Arg, |
src/zir.zig+3| ... | @@ -2330,6 +2330,9 @@ const EmitZIR = struct { | ... | @@ -2330,6 +2330,9 @@ const EmitZIR = struct { |
| 2330 | .cmp_neq => try self.emitBinOp(inst.src, new_body, inst.castTag(.cmp_neq).?, .cmp_neq), | 2330 | .cmp_neq => try self.emitBinOp(inst.src, new_body, inst.castTag(.cmp_neq).?, .cmp_neq), |
| 2331 | .booland => try self.emitBinOp(inst.src, new_body, inst.castTag(.booland).?, .booland), | 2331 | .booland => try self.emitBinOp(inst.src, new_body, inst.castTag(.booland).?, .booland), |
| 2332 | .boolor => try self.emitBinOp(inst.src, new_body, inst.castTag(.boolor).?, .boolor), | 2332 | .boolor => try self.emitBinOp(inst.src, new_body, inst.castTag(.boolor).?, .boolor), |
| 2333 | .bitand => try self.emitBinOp(inst.src, new_body, inst.castTag(.bitand).?, .bitand), | ||
| 2334 | .bitor => try self.emitBinOp(inst.src, new_body, inst.castTag(.bitor).?, .bitor), | ||
| 2335 | .xor => try self.emitBinOp(inst.src, new_body, inst.castTag(.xor).?, .xor), | ||
| 2333 | 2336 | ||
| 2334 | .bitcast => try self.emitCast(inst.src, new_body, inst.castTag(.bitcast).?, .bitcast), | 2337 | .bitcast => try self.emitCast(inst.src, new_body, inst.castTag(.bitcast).?, .bitcast), |
| 2335 | .intcast => try self.emitCast(inst.src, new_body, inst.castTag(.intcast).?, .intcast), | 2338 | .intcast => try self.emitCast(inst.src, new_body, inst.castTag(.intcast).?, .intcast), |
src/zir_sema.zig+61-2| ... | @@ -1458,7 +1458,66 @@ fn analyzeInstShr(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError | ... | @@ -1458,7 +1458,66 @@ fn analyzeInstShr(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError |
| 1458 | } | 1458 | } |
| 1459 | 1459 | ||
| 1460 | fn analyzeInstBitwise(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { | 1460 | fn analyzeInstBitwise(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { |
| 1461 | return mod.fail(scope, inst.base.src, "TODO implement analyzeInstBitwise", .{}); | 1461 | const tracy = trace(@src()); |
| 1462 | defer tracy.end(); | ||
| 1463 | |||
| 1464 | const lhs = try resolveInst(mod, scope, inst.positionals.lhs); | ||
| 1465 | const rhs = try resolveInst(mod, scope, inst.positionals.rhs); | ||
| 1466 | |||
| 1467 | const instructions = &[_]*Inst{ lhs, rhs }; | ||
| 1468 | const resolved_type = try mod.resolvePeerTypes(scope, instructions); | ||
| 1469 | const casted_lhs = try mod.coerce(scope, resolved_type, lhs); | ||
| 1470 | const casted_rhs = try mod.coerce(scope, resolved_type, rhs); | ||
| 1471 | |||
| 1472 | const scalar_type = if (resolved_type.zigTypeTag() == .Vector) | ||
| 1473 | resolved_type.elemType() | ||
| 1474 | else | ||
| 1475 | resolved_type; | ||
| 1476 | |||
| 1477 | const scalar_tag = scalar_type.zigTypeTag(); | ||
| 1478 | |||
| 1479 | if (lhs.ty.zigTypeTag() == .Vector and rhs.ty.zigTypeTag() == .Vector) { | ||
| 1480 | if (lhs.ty.arrayLen() != rhs.ty.arrayLen()) { | ||
| 1481 | return mod.fail(scope, inst.base.src, "vector length mismatch: {} and {}", .{ | ||
| 1482 | lhs.ty.arrayLen(), | ||
| 1483 | rhs.ty.arrayLen(), | ||
| 1484 | }); | ||
| 1485 | } | ||
| 1486 | return mod.fail(scope, inst.base.src, "TODO implement support for vectors in analyzeInstBitwise", .{}); | ||
| 1487 | } else if (lhs.ty.zigTypeTag() == .Vector or rhs.ty.zigTypeTag() == .Vector) { | ||
| 1488 | return mod.fail(scope, inst.base.src, "mixed scalar and vector operands to binary expression: '{}' and '{}'", .{ | ||
| 1489 | lhs.ty, | ||
| 1490 | rhs.ty, | ||
| 1491 | }); | ||
| 1492 | } | ||
| 1493 | |||
| 1494 | const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; | ||
| 1495 | |||
| 1496 | if (!is_int) { | ||
| 1497 | return mod.fail(scope, inst.base.src, "invalid operands to binary bitwise expression: '{}' and '{}'", .{ @tagName(lhs.ty.zigTypeTag()), @tagName(rhs.ty.zigTypeTag()) }); | ||
| 1498 | } | ||
| 1499 | |||
| 1500 | if (casted_lhs.value()) |lhs_val| { | ||
| 1501 | if (casted_rhs.value()) |rhs_val| { | ||
| 1502 | if (lhs_val.isUndef() or rhs_val.isUndef()) { | ||
| 1503 | return mod.constInst(scope, inst.base.src, .{ | ||
| 1504 | .ty = resolved_type, | ||
| 1505 | .val = Value.initTag(.undef), | ||
| 1506 | }); | ||
| 1507 | } | ||
| 1508 | return mod.fail(scope, inst.base.src, "TODO implement comptime bitwise operations", .{}); | ||
| 1509 | } | ||
| 1510 | } | ||
| 1511 | |||
| 1512 | const b = try mod.requireRuntimeBlock(scope, inst.base.src); | ||
| 1513 | const ir_tag = switch (inst.base.tag) { | ||
| 1514 | .bitand => Inst.Tag.bitand, | ||
| 1515 | .bitor => Inst.Tag.bitor, | ||
| 1516 | .xor => Inst.Tag.xor, | ||
| 1517 | else => unreachable, | ||
| 1518 | }; | ||
| 1519 | |||
| 1520 | return mod.addBinOp(b, inst.base.src, scalar_type, ir_tag, casted_lhs, casted_rhs); | ||
| 1462 | } | 1521 | } |
| 1463 | 1522 | ||
| 1464 | fn analyzeInstBitNot(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { | 1523 | 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 | ... | @@ -1501,7 +1560,7 @@ fn analyzeInstArithmetic(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) Inn |
| 1501 | } | 1560 | } |
| 1502 | return mod.fail(scope, inst.base.src, "TODO implement support for vectors in analyzeInstBinOp", .{}); | 1561 | return mod.fail(scope, inst.base.src, "TODO implement support for vectors in analyzeInstBinOp", .{}); |
| 1503 | } else if (lhs.ty.zigTypeTag() == .Vector or rhs.ty.zigTypeTag() == .Vector) { | 1562 | } else if (lhs.ty.zigTypeTag() == .Vector or rhs.ty.zigTypeTag() == .Vector) { |
| 1504 | return mod.fail(scope, inst.base.src, "mixed scalar and vector operands to comparison operator: '{}' and '{}'", .{ | 1563 | return mod.fail(scope, inst.base.src, "mixed scalar and vector operands to binary expression: '{}' and '{}'", .{ |
| 1505 | lhs.ty, | 1564 | lhs.ty, |
| 1506 | rhs.ty, | 1565 | rhs.ty, |
| 1507 | }); | 1566 | }); |