authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2021-05-20 13:05:32+02:00
committergravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2021-05-22 16:11:56+02:00
log6a121d9ccde34556ffb1baf3b8543defdf6136e0
treeb257848e5d00b142ab75966ffbca896bffd12908
parentb8444d2c51f334e3afec74ff80b051ed797ab480

SPIR-V: Split out genCmp from genBinOp


2 files changed, 58 insertions(+), 23 deletions(-)

src/codegen/spirv.zig+57-22
...@@ -348,7 +348,7 @@ pub const DeclGen = struct {...@@ -348,7 +348,7 @@ pub const DeclGen = struct {
348 const int_info = ty.intInfo(target);348 const int_info = ty.intInfo(target);
349 const backing_bits = self.backingIntBits(int_info.bits) orelse {349 const backing_bits = self.backingIntBits(int_info.bits) orelse {
350 // Integers too big for any native type are represented as "composite integers": An array of largestSupportedIntBits.350 // Integers too big for any native type are represented as "composite integers": An array of largestSupportedIntBits.
351 return self.fail(.{ .node_offset = 0 }, "TODO: SPIR-V backend: implement composite ints {}", .{ty});351 return self.fail(.{ .node_offset = 0 }, "TODO: SPIR-V backend: implement composite int {}", .{ty});
352 };352 };
353353
354 // TODO: If backing_bits != int_info.bits, a duplicate type might be generated here.354 // TODO: If backing_bits != int_info.bits, a duplicate type might be generated here.
...@@ -487,12 +487,12 @@ pub const DeclGen = struct {...@@ -487,12 +487,12 @@ pub const DeclGen = struct {
487 .bit_and => try self.genBinOp(inst.castTag(.bit_and).?),487 .bit_and => try self.genBinOp(inst.castTag(.bit_and).?),
488 .bit_or => try self.genBinOp(inst.castTag(.bit_or).?),488 .bit_or => try self.genBinOp(inst.castTag(.bit_or).?),
489 .xor => try self.genBinOp(inst.castTag(.xor).?),489 .xor => try self.genBinOp(inst.castTag(.xor).?),
490 .cmp_eq => try self.genBinOp(inst.castTag(.cmp_eq).?),490 .cmp_eq => try self.genCmp(inst.castTag(.cmp_eq).?),
491 .cmp_neq => try self.genBinOp(inst.castTag(.cmp_neq).?),491 .cmp_neq => try self.genCmp(inst.castTag(.cmp_neq).?),
492 .cmp_gt => try self.genBinOp(inst.castTag(.cmp_gt).?),492 .cmp_gt => try self.genCmp(inst.castTag(.cmp_gt).?),
493 .cmp_gte => try self.genBinOp(inst.castTag(.cmp_gte).?),493 .cmp_gte => try self.genCmp(inst.castTag(.cmp_gte).?),
494 .cmp_lt => try self.genBinOp(inst.castTag(.cmp_lt).?),494 .cmp_lt => try self.genCmp(inst.castTag(.cmp_lt).?),
495 .cmp_lte => try self.genBinOp(inst.castTag(.cmp_lte).?),495 .cmp_lte => try self.genCmp(inst.castTag(.cmp_lte).?),
496 .bool_and => try self.genBinOp(inst.castTag(.bool_and).?),496 .bool_and => try self.genBinOp(inst.castTag(.bool_and).?),
497 .bool_or => try self.genBinOp(inst.castTag(.bool_or).?),497 .bool_or => try self.genBinOp(inst.castTag(.bool_or).?),
498 .not => try self.genUnOp(inst.castTag(.not).?),498 .not => try self.genUnOp(inst.castTag(.not).?),
...@@ -504,7 +504,7 @@ pub const DeclGen = struct {...@@ -504,7 +504,7 @@ pub const DeclGen = struct {
504 .ret => self.genRet(inst.castTag(.ret).?),504 .ret => self.genRet(inst.castTag(.ret).?),
505 .retvoid => self.genRetVoid(),505 .retvoid => self.genRetVoid(),
506 .unreach => self.genUnreach(),506 .unreach => self.genUnreach(),
507 else => self.fail(.{ .node_offset = 0 }, "TODO: SPIR-V backend: implement inst {}", .{inst.tag}),507 else => self.fail(inst.src, "TODO: SPIR-V backend: implement inst {s}", .{@tagName(inst.tag)}),
508 };508 };
509 }509 }
510510
...@@ -528,13 +528,14 @@ pub const DeclGen = struct {...@@ -528,13 +528,14 @@ pub const DeclGen = struct {
528 const info = try self.arithmeticTypeInfo(inst.lhs.ty);528 const info = try self.arithmeticTypeInfo(inst.lhs.ty);
529529
530 if (info.class == .composite_integer)530 if (info.class == .composite_integer)
531 return self.fail(.{ .node_offset = 0 }, "TODO: SPIR-V backend: binary operations for composite integers", .{});531 return self.fail(inst.base.src, "TODO: SPIR-V backend: binary operations for composite integers", .{});
532 else if (info.class == .strange_integer)
533 return self.fail(inst.base.src, "TODO: SPIR-V backend: binary operations for strange integers", .{});
532534
533 const is_bool = info.class == .bool;535 const is_bool = info.class == .bool;
534 const is_float = info.class == .float;536 const is_float = info.class == .float;
535 const is_signed = info.signedness == .signed;537 const is_signed = info.signedness == .signed;
536 // **Note**: All these operations must be valid for vectors of floats, integers and bools as well!538 // **Note**: All these operations must be valid for vectors as well!
537 // For floating points, we generally want ordered operations (which return false if either operand is nan).
538 const opcode = switch (inst.base.tag) {539 const opcode = switch (inst.base.tag) {
539 // The regular integer operations are all defined for wrapping. Since theyre only relevant for integers,540 // The regular integer operations are all defined for wrapping. Since theyre only relevant for integers,
540 // we can just switch on both cases here.541 // we can just switch on both cases here.
...@@ -551,16 +552,6 @@ pub const DeclGen = struct {...@@ -551,16 +552,6 @@ pub const DeclGen = struct {
551 .bit_and => Opcode.OpBitwiseAnd,552 .bit_and => Opcode.OpBitwiseAnd,
552 .bit_or => Opcode.OpBitwiseOr,553 .bit_or => Opcode.OpBitwiseOr,
553 .xor => Opcode.OpBitwiseXor,554 .xor => Opcode.OpBitwiseXor,
554 // Int/bool/float -> bool operations.
555 .cmp_eq => if (is_float) Opcode.OpFOrdEqual else if (is_bool) Opcode.OpLogicalEqual else Opcode.OpIEqual,
556 .cmp_neq => if (is_float) Opcode.OpFOrdNotEqual else if (is_bool) Opcode.OpLogicalNotEqual else Opcode.OpINotEqual,
557 // Int/float -> bool operations.
558 // TODO: Verify that these OpFOrd type operations produce the right value.
559 // TODO: Is there a more fundamental difference between OpU and OpS operations here than just the type?
560 .cmp_gt => if (is_float) Opcode.OpFOrdGreaterThan else if (is_signed) Opcode.OpSGreaterThan else Opcode.OpUGreaterThan,
561 .cmp_gte => if (is_float) Opcode.OpFOrdGreaterThanEqual else if (is_signed) Opcode.OpSGreaterThanEqual else Opcode.OpUGreaterThanEqual,
562 .cmp_lt => if (is_float) Opcode.OpFOrdLessThan else if (is_signed) Opcode.OpSLessThan else Opcode.OpULessThan,
563 .cmp_lte => if (is_float) Opcode.OpFOrdLessThanEqual else if (is_signed) Opcode.OpSLessThanEqual else Opcode.OpULessThanEqual,
564 // Bool -> bool operations.555 // Bool -> bool operations.
565 .bool_and => Opcode.OpLogicalAnd,556 .bool_and => Opcode.OpLogicalAnd,
566 .bool_or => Opcode.OpLogicalOr,557 .bool_or => Opcode.OpLogicalOr,
...@@ -575,7 +566,51 @@ pub const DeclGen = struct {...@@ -575,7 +566,51 @@ pub const DeclGen = struct {
575 if (info.class != .strange_integer)566 if (info.class != .strange_integer)
576 return result_id;567 return result_id;
577568
578 return self.fail(.{ .node_offset = 0 }, "TODO: SPIR-V backend: strange integer operation mask", .{});569 return self.fail(inst.base.src, "TODO: SPIR-V backend: strange integer operation mask", .{});
570 }
571
572 fn genCmp(self: *DeclGen, inst: *Inst.BinOp) !ResultId {
573 const lhs_id = try self.resolve(inst.lhs);
574 const rhs_id = try self.resolve(inst.rhs);
575
576 const result_id = self.spv.allocResultId();
577 const result_type_id = try self.getOrGenType(inst.base.ty);
578
579 // All of these operations should be 2 equal types -> bool
580 std.debug.assert(inst.rhs.ty.eql(inst.lhs.ty));
581 std.debug.assert(inst.base.ty.tag() == .bool);
582
583 // Comparisons are generally applicable to both scalar and vector operations in SPIR-V, but int and float
584 // versions of operations require different opcodes.
585 // Since inst.base.ty is always bool and so not very useful, and because both arguments must be the same, just get the info
586 // from either of the operands.
587 const info = try self.arithmeticTypeInfo(inst.lhs.ty);
588
589 if (info.class == .composite_integer)
590 return self.fail(inst.base.src, "TODO: SPIR-V backend: binary operations for composite integers", .{});
591 else if (info.class == .strange_integer)
592 return self.fail(inst.base.src, "TODO: SPIR-V backend: comparison for strange integers", .{});
593
594 const is_bool = info.class == .bool;
595 const is_float = info.class == .float;
596 const is_signed = info.signedness == .signed;
597
598 // **Note**: All these operations must be valid for vectors as well!
599 // For floating points, we generally want ordered operations (which return false if either operand is nan).
600 const opcode = switch (inst.base.tag) {
601 .cmp_eq => if (is_float) Opcode.OpFOrdEqual else if (is_bool) Opcode.OpLogicalEqual else Opcode.OpIEqual,
602 .cmp_neq => if (is_float) Opcode.OpFOrdNotEqual else if (is_bool) Opcode.OpLogicalNotEqual else Opcode.OpINotEqual,
603 // TODO: Verify that these OpFOrd type operations produce the right value.
604 // TODO: Is there a more fundamental difference between OpU and OpS operations here than just the type?
605 .cmp_gt => if (is_float) Opcode.OpFOrdGreaterThan else if (is_signed) Opcode.OpSGreaterThan else Opcode.OpUGreaterThan,
606 .cmp_gte => if (is_float) Opcode.OpFOrdGreaterThanEqual else if (is_signed) Opcode.OpSGreaterThanEqual else Opcode.OpUGreaterThanEqual,
607 .cmp_lt => if (is_float) Opcode.OpFOrdLessThan else if (is_signed) Opcode.OpSLessThan else Opcode.OpULessThan,
608 .cmp_lte => if (is_float) Opcode.OpFOrdLessThanEqual else if (is_signed) Opcode.OpSLessThanEqual else Opcode.OpULessThanEqual,
609 else => unreachable,
610 };
611
612 try writeInstruction(&self.spv.binary.fn_decls, opcode, &[_]Word{ result_type_id, result_id, lhs_id, rhs_id });
613 return result_id;
579 }614 }
580615
581 fn genUnOp(self: *DeclGen, inst: *Inst.UnOp) !ResultId {616 fn genUnOp(self: *DeclGen, inst: *Inst.UnOp) !ResultId {
src/link/SpirV.zig+1-1
...@@ -41,7 +41,7 @@ const spec = @import("../codegen/spirv/spec.zig");...@@ -41,7 +41,7 @@ const spec = @import("../codegen/spirv/spec.zig");
41pub const FnData = struct {41pub const FnData = struct {
42 // We're going to fill these in flushModule, and we're going to fill them unconditionally,42 // We're going to fill these in flushModule, and we're going to fill them unconditionally,
43 // so just set it to undefined.43 // so just set it to undefined.
44 id: ResultId = undefined44 id: ResultId = undefined,
45};45};
4646
47base: link.File,47base: link.File,