return ac_build_intrinsic(ctx, intr, type, params, 1,
                                  AC_FUNC_ATTR_READNONE);
 }
+
+/*
+ * this takes an I,J coordinate pair,
+ * and works out the X and Y derivatives.
+ * it returns DDX(I), DDX(J), DDY(I), DDY(J).
+ */
+LLVMValueRef
+ac_build_ddxy_interp(struct ac_llvm_context *ctx, LLVMValueRef interp_ij)
+{
+       LLVMValueRef result[4], a;
+       unsigned i;
+
+       for (i = 0; i < 2; i++) {
+               a = LLVMBuildExtractElement(ctx->builder, interp_ij,
+                                           LLVMConstInt(ctx->i32, i, false), "");
+               result[i] = ac_build_ddxy(ctx, AC_TID_MASK_TOP_LEFT, 1, a);
+               result[2+i] = ac_build_ddxy(ctx, AC_TID_MASK_TOP_LEFT, 2, a);
+       }
+       return ac_build_gather_values(ctx, result, 4);
+}
 
 ac_build_frexp_mant(struct ac_llvm_context *ctx, LLVMValueRef src0,
                    unsigned bitsize);
 
+LLVMValueRef
+ac_build_ddxy_interp(struct ac_llvm_context *ctx, LLVMValueRef interp_ij);
+
 #ifdef __cplusplus
 }
 #endif
 
        return result;
 }
 
-/*
- * this takes an I,J coordinate pair,
- * and works out the X and Y derivatives.
- * it returns DDX(I), DDX(J), DDY(I), DDY(J).
- */
-static LLVMValueRef emit_ddxy_interp(
-       struct ac_nir_context *ctx,
-       LLVMValueRef interp_ij)
-{
-       LLVMValueRef result[4], a;
-       unsigned i;
-
-       for (i = 0; i < 2; i++) {
-               a = LLVMBuildExtractElement(ctx->ac.builder, interp_ij,
-                                           LLVMConstInt(ctx->ac.i32, i, false), "");
-               result[i] = emit_ddxy(ctx, nir_op_fddx, a);
-               result[2+i] = emit_ddxy(ctx, nir_op_fddy, a);
-       }
-       return ac_build_gather_values(&ctx->ac, result, 4);
-}
-
 static void visit_alu(struct ac_nir_context *ctx, const nir_alu_instr *instr)
 {
        LLVMValueRef src[4], result = NULL;
 
        if (location == INTERP_CENTER) {
                LLVMValueRef ij_out[2];
-               LLVMValueRef ddxy_out = emit_ddxy_interp(ctx, interp_param);
+               LLVMValueRef ddxy_out = ac_build_ddxy_interp(&ctx->ac, interp_param);
 
                /*
                 * take the I then J parameters, and the DDX/Y for it, and
 
        emit_data->output[emit_data->chan] = val;
 }
 
-/*
- * this takes an I,J coordinate pair,
- * and works out the X and Y derivatives.
- * it returns DDX(I), DDX(J), DDY(I), DDY(J).
- */
-static LLVMValueRef si_llvm_emit_ddxy_interp(
-       struct lp_build_tgsi_context *bld_base,
-       LLVMValueRef interp_ij)
-{
-       struct si_shader_context *ctx = si_shader_context(bld_base);
-       LLVMValueRef result[4], a;
-       unsigned i;
-
-       for (i = 0; i < 2; i++) {
-               a = LLVMBuildExtractElement(ctx->ac.builder, interp_ij,
-                                           LLVMConstInt(ctx->i32, i, 0), "");
-               result[i] = ac_build_ddxy(&ctx->ac, AC_TID_MASK_TOP_LEFT, 1,
-                                         ac_to_integer(&ctx->ac, a)); /* DDX */
-               result[2+i] = ac_build_ddxy(&ctx->ac, AC_TID_MASK_TOP_LEFT, 2,
-                                           ac_to_integer(&ctx->ac, a)); /* DDY */
-       }
-
-       return ac_build_gather_values(&ctx->ac, result, 4);
-}
-
 static void build_interp_intrinsic(const struct lp_build_tgsi_action *action,
                                struct lp_build_tgsi_context *bld_base,
                                struct lp_build_emit_data *emit_data)
        if (inst->Instruction.Opcode == TGSI_OPCODE_INTERP_OFFSET ||
            inst->Instruction.Opcode == TGSI_OPCODE_INTERP_SAMPLE) {
                LLVMValueRef ij_out[2];
-               LLVMValueRef ddxy_out = si_llvm_emit_ddxy_interp(bld_base, interp_param);
+               LLVMValueRef ddxy_out = ac_build_ddxy_interp(&ctx->ac, interp_param);
 
                /*
                 * take the I then J parameters, and the DDX/Y for it, and