-binop("seq", tfloat, commutative, "(src0 == src1) ? 1.0f : 0.0f") # Set on Equal
-binop("sne", tfloat, commutative, "(src0 != src1) ? 1.0f : 0.0f") # Set on Not Equal
-
-
-binop("ishl", tint, "", "src0 << src1")
-binop("ishr", tint, "", "src0 >> src1")
-binop("ushr", tuint, "", "src0 >> src1")
+binop("seq", tfloat32, _2src_commutative, "(src0 == src1) ? 1.0f : 0.0f") # Set on Equal
+binop("sne", tfloat32, _2src_commutative, "(src0 != src1) ? 1.0f : 0.0f") # Set on Not Equal
+
+# SPIRV shifts are undefined for shift-operands >= bitsize,
+# but SM5 shifts are defined to use the least significant bits, only
+# The NIR definition is according to the SM5 specification.
+opcode("ishl", 0, tint, [0, 0], [tint, tuint32], False, "",
+ "src0 << (src1 & (sizeof(src0) * 8 - 1))")
+opcode("ishr", 0, tint, [0, 0], [tint, tuint32], False, "",
+ "src0 >> (src1 & (sizeof(src0) * 8 - 1))")
+opcode("ushr", 0, tuint, [0, 0], [tuint, tuint32], False, "",
+ "src0 >> (src1 & (sizeof(src0) * 8 - 1))")
+
+opcode("urol", 0, tuint, [0, 0], [tuint, tuint32], False, "", """
+ uint32_t rotate_mask = sizeof(src0) * 8 - 1;
+ dst = (src0 << (src1 & rotate_mask)) |
+ (src0 >> (-src1 & rotate_mask));
+""")
+opcode("uror", 0, tuint, [0, 0], [tuint, tuint32], False, "", """
+ uint32_t rotate_mask = sizeof(src0) * 8 - 1;
+ dst = (src0 >> (src1 & rotate_mask)) |
+ (src0 << (-src1 & rotate_mask));
+""")