diff --git a/benches/bench.rs b/benches/bench.rs
index 07fd9b402ccd58c6a60e17a153df0ee85e4c21d8..f9ede03a36c1c0acb85f7d632bc27db8fa35a40a 100644
--- a/benches/bench.rs
+++ b/benches/bench.rs
@@ -13,6 +13,7 @@ extern crate rand;
 extern crate rav1e;
 
 mod predict;
+mod transform;
 mod me;
 
 use criterion::*;
@@ -24,6 +25,8 @@ use rav1e::predict::*;
 use rav1e::rdo::rdo_cfl_alpha;
 use rav1e::*;
 
+use transform::transform;
+
 #[cfg(feature = "comparative_bench")]
 mod comparative;
 
@@ -145,4 +148,4 @@ criterion_group!(me, me::get_sad);
 criterion_main!(comparative::intra_prediction);
 
 #[cfg(not(feature = "comparative_bench"))]
-criterion_main!(write_block, intra_prediction, cdef, cfl, me);
+criterion_main!(write_block, intra_prediction, cdef, cfl, me, transform);
diff --git a/benches/transform.rs b/benches/transform.rs
new file mode 100644
index 0000000000000000000000000000000000000000..d3d9783e27ed2ce067791d4e8181980342de97e9
--- /dev/null
+++ b/benches/transform.rs
@@ -0,0 +1,50 @@
+// Copyright (c) 2017-2018, The rav1e contributors. All rights reserved
+//
+// This source code is subject to the terms of the BSD 2 Clause License and
+// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
+// was not distributed with this source code in the LICENSE file, you can
+// obtain it at www.aomedia.org/license/software. If the Alliance for Open
+// Media Patent License 1.0 was not distributed with this source code in the
+// PATENTS file, you can obtain it at www.aomedia.org/license/patent.
+
+use criterion::*;
+use rand::{ChaChaRng, Rng, SeedableRng};
+use rav1e::transform;
+
+fn bench_idct4(b: &mut Bencher, bit_depth: &usize) {
+  let mut ra = ChaChaRng::from_seed([0; 32]);
+  let input: [i32; 4] = ra.gen();
+  let mut output = [0i32; 4];
+  let range = bit_depth + 8;
+
+  b.iter(|| {
+    transform::av1_idct4(&input[..], &mut output[..], range);
+  });
+}
+
+pub fn av1_idct4(c: &mut Criterion) {
+  let plain = Fun::new("plain", bench_idct4);
+  let funcs = vec![plain];
+
+  c.bench_functions("av1_idct4_8", funcs, 8);
+}
+
+fn bench_idct8(b: &mut Bencher, bit_depth: &usize) {
+  let mut ra = ChaChaRng::from_seed([0; 32]);
+  let input: [i32; 8] = ra.gen();
+  let mut output = [0i32; 8];
+  let range = bit_depth + 8;
+
+  b.iter(|| {
+    transform::av1_idct8(&input[..], &mut output[..], range);
+  });
+}
+
+pub fn av1_idct8(c: &mut Criterion) {
+  let plain = Fun::new("plain", bench_idct8);
+  let funcs = vec![plain];
+
+  c.bench_functions("av1_idct8_8", funcs, 8);
+}
+
+criterion_group!(transform, av1_idct4, av1_idct8);
diff --git a/src/transform.rs b/src/transform.rs
index c9c467050f3fcf6980d355302463fbc387a25eab..10467e6f3ecf8855845d9f2947f0cfa0f6da4301 100644
--- a/src/transform.rs
+++ b/src/transform.rs
@@ -56,7 +56,7 @@ fn clamp_value(value: i32, bit: usize) -> i32 {
   clamp(value, min_value, max_value)
 }
 
-fn av1_idct4(input: &[i32], output: &mut [i32], range: usize) {
+pub fn av1_idct4(input: &[i32], output: &mut [i32], range: usize) {
   let cos_bit = 12;
   // stage 0
 
@@ -129,7 +129,7 @@ fn av1_iidentity4(input: &[i32], output: &mut [i32], _range: usize) {
   }
 }
 
-fn av1_idct8(input: &[i32], output: &mut [i32], range: usize) {
+pub fn av1_idct8(input: &[i32], output: &mut [i32], range: usize) {
   // TODO: call idct4
   let cos_bit = 12;
   // stage 0