authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2021-05-16 14:46:58+02:00
committergravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2021-05-16 14:46:58+02:00
log585122b1ac51f9ac23bae537dfc40bbae1d7cb3c
tree8cebec3bde9cff4e52058a322c1a0b20bb2e801a
parentf14000c7e1bd9032185b3c0a2a28a73eec6c48f7

SPIR-V: comparison and equality operations


1 files changed, 36 insertions(+), 3 deletions(-)

src/codegen/spirv.zig+36-3
......@@ -84,6 +84,9 @@ pub const DeclGen = struct {
8484 const ArithmeticTypeInfo = struct {
8585 /// A classification of the inner type.
8686 const Class = enum {
87 /// A boolean.
88 bool,
89
8790 /// A regular, **native**, integer.
8891 /// This is only returned when the backend supports this int as a native type (when
8992 /// the relevant capability is enabled).
......@@ -196,6 +199,12 @@ pub const DeclGen = struct {
196199 const target = self.module.getTarget();
197200
198201 return switch (ty.zigTypeTag()) {
202 .Bool => ArithmeticTypeInfo{
203 .bits = 1, // Doesn't matter for this class.
204 .is_vector = false,
205 .signedness = .unsigned, // Technically, but doesn't matter for this class.
206 .class = .bool,
207 },
199208 .Float => ArithmeticTypeInfo{
200209 .bits = ty.floatBits(target),
201210 .is_vector = false,
......@@ -436,6 +445,12 @@ pub const DeclGen = struct {
436445 .bit_and => try self.genBinOp(inst.castTag(.bit_and).?),
437446 .bit_or => try self.genBinOp(inst.castTag(.bit_or).?),
438447 .xor => try self.genBinOp(inst.castTag(.xor).?),
448 .cmp_eq => try self.genBinOp(inst.castTag(.cmp_eq).?),
449 .cmp_neq => try self.genBinOp(inst.castTag(.cmp_neq).?),
450 .cmp_gt => try self.genBinOp(inst.castTag(.cmp_gt).?),
451 .cmp_gte => try self.genBinOp(inst.castTag(.cmp_gte).?),
452 .cmp_lt => try self.genBinOp(inst.castTag(.cmp_lt).?),
453 .cmp_lte => try self.genBinOp(inst.castTag(.cmp_lte).?),
439454 .arg => self.genArg(),
440455 // TODO: Breakpoints won't be supported in SPIR-V, but the compiler seems to insert them
441456 // throughout the IR.
......@@ -458,18 +473,23 @@ pub const DeclGen = struct {
458473
459474 // TODO: Is the result the same as the argument types?
460475 // This is supposed to be the case for SPIR-V.
461 std.debug.assert(inst.base.ty.eql(inst.lhs.ty) and inst.base.ty.eql(inst.rhs.ty));
476 std.debug.assert(inst.rhs.ty.eql(inst.lhs.ty));
477 std.debug.assert(inst.base.ty.tag() == .bool or inst.base.ty.eql(inst.lhs.ty));
462478
463479 // Binary operations are generally applicable to both scalar and vector operations in SPIR-V, but int and float
464480 // versions of operations require different opcodes.
465 const info = try self.arithmeticTypeInfo(inst.base.ty);
481 // For operations which produce bools, the information of inst.base.ty is not useful, so just pick either operand
482 // instead.
483 const info = try self.arithmeticTypeInfo(inst.lhs.ty);
466484
467485 if (info.class == .composite_integer)
468486 return self.fail(.{.node_offset = 0}, "TODO: SPIR-V backend: binary operations for composite integers", .{});
469487
488 const is_bool = info.class == .bool;
470489 const is_float = info.class == .float;
471490 const is_signed = info.signedness == .signed;
472 // **Note**: All these operations must be valid for vectors of floats and integers as well!
491 // **Note**: All these operations must be valid for vectors of floats, integers and bools as well!
492 // For floating points, we generally want ordered operations (which return false if either operand is nan).
473493 const opcode = switch (inst.base.tag) {
474494 // The regular integer operations are all defined for wrapping. Since theyre only relevant for integers,
475495 // we can just switch on both cases here.
......@@ -478,11 +498,24 @@ pub const DeclGen = struct {
478498 .mul, .mulwrap => if (is_float) Opcode.OpFMul else Opcode.OpIMul,
479499 // TODO: Trap if divisor is 0?
480500 // TODO: Figure out of OpSDiv for unsigned/OpUDiv for signed does anything useful.
501 // => Those are probably for divTrunc and divFloor, though the compiler does not yet generate those.
502 // => TODO: Figure out how those work on the SPIR-V side.
503 // => TODO: Test these.
481504 .div => if (is_float) Opcode.OpFDiv else if (is_signed) Opcode.OpSDiv else Opcode.OpUDiv,
482505 // Only integer versions for these.
483506 .bit_and => Opcode.OpBitwiseAnd,
484507 .bit_or => Opcode.OpBitwiseOr,
485508 .xor => Opcode.OpBitwiseXor,
509 // Int/bool/float -> bool operations.
510 .cmp_eq => if (is_float) Opcode.OpFOrdEqual else if (is_bool) Opcode.OpLogicalEqual else Opcode.OpIEqual,
511 .cmp_neq => if (is_float) Opcode.OpFOrdNotEqual else if (is_bool) Opcode.OpLogicalNotEqual else Opcode.OpINotEqual,
512 // Int/float -> bool operations.
513 // TODO: Verify that these OpFOrd type operations produce the right value.
514 // TODO: Is there a more fundamental difference between OpU and OpS operations here than just the type?
515 .cmp_gt => if (is_float) Opcode.OpFOrdGreaterThan else if (is_signed) Opcode.OpSGreaterThan else Opcode.OpUGreaterThan,
516 .cmp_gte => if (is_float) Opcode.OpFOrdGreaterThanEqual else if (is_signed) Opcode.OpSGreaterThanEqual else Opcode.OpUGreaterThanEqual,
517 .cmp_lt => if (is_float) Opcode.OpFOrdLessThan else if (is_signed) Opcode.OpSLessThan else Opcode.OpULessThan,
518 .cmp_lte => if (is_float) Opcode.OpFOrdLessThanEqual else if (is_signed) Opcode.OpSLessThanEqual else Opcode.OpULessThanEqual,
486519 else => unreachable,
487520 };
488521