+ return qir_MOV(c, qir_SEL(c, QPU_COND_NS, src[1], src[2]));
+}
+
+static struct qreg
+ntq_fddx(struct vc4_compile *c, struct qreg src)
+{
+ /* Make sure that we have a bare temp to use for MUL rotation, so it
+ * can be allocated to an accumulator.
+ */
+ if (src.pack || src.file != QFILE_TEMP)
+ src = qir_MOV(c, src);
+
+ struct qreg from_left = qir_ROT_MUL(c, src, 1);
+ struct qreg from_right = qir_ROT_MUL(c, src, 15);
+
+ /* Distinguish left/right pixels of the quad. */
+ qir_SF(c, qir_AND(c, qir_reg(QFILE_QPU_ELEMENT, 0),
+ qir_uniform_ui(c, 1)));
+
+ return qir_MOV(c, qir_SEL(c, QPU_COND_ZS,
+ qir_FSUB(c, from_right, src),
+ qir_FSUB(c, src, from_left)));
+}
+
+static struct qreg
+ntq_fddy(struct vc4_compile *c, struct qreg src)
+{
+ if (src.pack || src.file != QFILE_TEMP)
+ src = qir_MOV(c, src);
+
+ struct qreg from_bottom = qir_ROT_MUL(c, src, 2);
+ struct qreg from_top = qir_ROT_MUL(c, src, 14);
+
+ /* Distinguish top/bottom pixels of the quad. */
+ qir_SF(c, qir_AND(c,
+ qir_reg(QFILE_QPU_ELEMENT, 0),
+ qir_uniform_ui(c, 2)));
+
+ return qir_MOV(c, qir_SEL(c, QPU_COND_ZS,
+ qir_FSUB(c, from_top, src),
+ qir_FSUB(c, src, from_bottom)));