{"action":"created","comment":{"url":"https://api.github.com/repos/Cretonne/cretonne/pulls/comments/170709971","pull_request_review_id":99410135,"id":170709971,"diff_hunk":"@@ -0,0 +1,1051 @@\n+//! A pre-legalization rewriting pass\n+\n+#![allow(non_snake_case)]\n+\n+use cursor::{Cursor, FuncCursor};\n+use ir::dfg::ValueDef;\n+use ir::{Function, InstructionData, Value, DataFlowGraph, InstBuilder, Type};\n+use ir::Inst;\n+use ir::types::{I32, I64};\n+use ir::instructions::Opcode;\n+\n+\n+//----------------------------------------------------------------------\n+//\n+// Math helpers for division by (non-power-of-2) constants.  This is based\n+// on the presentation in \"Hacker's Delight\" by Henry Warren, 2003.  There\n+// are four cases: {unsigned, signed} x {32 bit, 64 bit}.  The word size\n+// makes little difference, but the signed-vs-unsigned aspect has a large\n+// effect.  Therefore everything is presented in the order U32 U64 S32 S64\n+// so as to emphasise the similarity of the U32 and U64 cases and the S32\n+// and S64 cases.\n+\n+// Structures to hold the \"magic numbers\" computed.\n+\n+#[derive(PartialEq, Debug)]\n+struct MU32 {\n+    mulBy: u32,\n+    doAdd: bool,\n+    shiftBy: i32,\n+}\n+\n+#[derive(PartialEq, Debug)]\n+struct MU64 {\n+    mulBy: u64,\n+    doAdd: bool,\n+    shiftBy: i32,\n+}\n+\n+#[derive(PartialEq, Debug)]\n+struct MS32 {\n+    mulBy: i32,\n+    shiftBy: i32,\n+}\n+\n+#[derive(PartialEq, Debug)]\n+struct MS64 {\n+    mulBy: i64,\n+    shiftBy: i32,\n+}\n+\n+// Simple math helpers\n+\n+#[inline]\n+// if |x| is a power of two, or the negation thereof, return the power along\n+// with a boolean that indicates whether |x| is negative.  Else return None.\n+fn isPowerOf2_S32(x: i32) -> Option<(bool, u32)> {\n+    // We have to special-case this because abs(x) isn't representable.\n+    if x == -0x8000_0000 {\n+        return Some((true, 31));\n+    }\n+    let abs_x = i32::wrapping_abs(x);\n+    if abs_x.count_ones() == 1 {\n+        return Some((x < 0, abs_x.trailing_zeros()));\n+    }\n+    None\n+}\n+\n+#[inline]\n+// Same comments as for isPowerOf2_S64 apply.\n+fn isPowerOf2_S64(x: i64) -> Option<(bool, u32)> {\n+    // We have to special-case this because abs(x) isn't representable.\n+    if x == -0x8000_0000_0000_0000 {\n+        return Some((true, 63));\n+    }\n+    let abs_x = i64::wrapping_abs(x);\n+    if abs_x.count_ones() == 1 {\n+        return Some((x < 0, abs_x.trailing_zeros()));\n+    }\n+    None\n+}\n+\n+// The actual \"magic number\" generators follow.\n+\n+fn magicU32(d: u32) -> MU32 {\n+    assert_ne!(d, 0);\n+    assert_ne!(d, 1); // d==1 generates out of range shifts.\n+\n+    let mut do_add: bool = false;\n+    let mut p: i32 = 31;\n+    let nc: u32 = 0xFFFFFFFFu32 - u32::wrapping_neg(d) % d;\n+    let mut q1: u32 = 0x80000000u32 / nc;\n+    let mut r1: u32 = 0x80000000u32 - q1 * nc;\n+    let mut q2: u32 = 0x7FFFFFFFu32 / d;\n+    let mut r2: u32 = 0x7FFFFFFFu32 - q2 * d;\n+    loop {\n+        p = p + 1;\n+        if r1 >= nc - r1 {\n+            q1 = u32::wrapping_add(u32::wrapping_mul(2, q1), 1);\n+            r1 = u32::wrapping_sub(u32::wrapping_mul(2, r1), nc);\n+        } else {\n+            q1 = 2 * q1;\n+            r1 = 2 * r1;\n+        }\n+        if r2 + 1 >= d - r2 {\n+            if q2 >= 0x7FFFFFFFu32 {\n+                do_add = true;\n+            }\n+            q2 = 2 * q2 + 1;\n+            r2 = u32::wrapping_sub(u32::wrapping_add(u32::wrapping_mul(2, r2), 1), d);\n+        } else {\n+            if q2 >= 0x80000000u32 {\n+                do_add = true;\n+            }\n+            q2 = u32::wrapping_mul(2, q2);\n+            r2 = 2 * r2 + 1;\n+        }\n+        let delta: u32 = d - 1 - r2;\n+        if !(p < 64 && (q1 < delta || (q1 == delta && r1 == 0))) {\n+            break;\n+        }\n+    }\n+\n+    MU32 {\n+        mulBy: q2 + 1,\n+        doAdd: do_add,\n+        shiftBy: p - 32,\n+    }\n+}\n+\n+fn magicU64(d: u64) -> MU64 {\n+    assert_ne!(d, 0);\n+    assert_ne!(d, 1); // d==1 generates out of range shifts.\n+\n+    let mut do_add: bool = false;\n+    let mut p: i32 = 63;\n+    let nc: u64 = 0xFFFFFFFFFFFFFFFFu64 - u64::wrapping_neg(d) % d;\n+    let mut q1: u64 = 0x8000000000000000u64 / nc;\n+    let mut r1: u64 = 0x8000000000000000u64 - q1 * nc;\n+    let mut q2: u64 = 0x7FFFFFFFFFFFFFFFu64 / d;\n+    let mut r2: u64 = 0x7FFFFFFFFFFFFFFFu64 - q2 * d;\n+    loop {\n+        p = p + 1;\n+        if r1 >= nc - r1 {\n+            q1 = u64::wrapping_add(u64::wrapping_mul(2, q1), 1);\n+            r1 = u64::wrapping_sub(u64::wrapping_mul(2, r1), nc);\n+        } else {\n+            q1 = 2 * q1;\n+            r1 = 2 * r1;\n+        }\n+        if r2 + 1 >= d - r2 {\n+            if q2 >= 0x7FFFFFFFFFFFFFFFu64 {\n+                do_add = true;\n+            }\n+            q2 = 2 * q2 + 1;\n+            r2 = u64::wrapping_sub(u64::wrapping_add(u64::wrapping_mul(2, r2), 1), d);\n+        } else {\n+            if q2 >= 0x8000000000000000u64 {\n+                do_add = true;\n+            }\n+            q2 = u64::wrapping_mul(2, q2);\n+            r2 = 2 * r2 + 1;\n+        }\n+        let delta: u64 = d - 1 - r2;\n+        if !(p < 128 && (q1 < delta || (q1 == delta && r1 == 0))) {\n+            break;\n+        }\n+    }\n+\n+    MU64 {\n+        mulBy: q2 + 1,\n+        doAdd: do_add,\n+        shiftBy: p - 64,\n+    }\n+}\n+\n+fn magicS32(d: i32) -> MS32 {\n+    assert_ne!(d, -1);\n+    assert_ne!(d, 0);\n+    assert_ne!(d, 1);\n+    let two31: u32 = 0x80000000u32;\n+    let mut p: i32 = 31;\n+    let ad: u32 = i32::wrapping_abs(d) as u32;\n+    let t: u32 = two31 + ((d as u32) >> 31);\n+    let anc: u32 = u32::wrapping_sub(t - 1, t % ad);\n+    let mut q1: u32 = two31 / anc;\n+    let mut r1: u32 = two31 - q1 * anc;\n+    let mut q2: u32 = two31 / ad;\n+    let mut r2: u32 = two31 - q2 * ad;\n+    loop {\n+        p = p + 1;\n+        q1 = 2 * q1;\n+        r1 = 2 * r1;\n+        if r1 >= anc {\n+            q1 = q1 + 1;\n+            r1 = r1 - anc;\n+        }\n+        q2 = 2 * q2;\n+        r2 = 2 * r2;\n+        if r2 >= ad {\n+            q2 = q2 + 1;\n+            r2 = r2 - ad;\n+        }\n+        let delta: u32 = ad - r2;\n+        if !(q1 < delta || (q1 == delta && r1 == 0)) {\n+            break;\n+        }\n+    }\n+\n+    MS32 {\n+        mulBy: (if d < 0 {\n+                    u32::wrapping_neg(q2 + 1)\n+                } else {\n+                    q2 + 1\n+                }) as i32,\n+        shiftBy: p - 32,\n+    }\n+}\n+\n+fn magicS64(d: i64) -> MS64 {\n+    assert_ne!(d, -1);\n+    assert_ne!(d, 0);\n+    assert_ne!(d, 1);\n+    let two63: u64 = 0x8000000000000000u64;\n+    let mut p: i32 = 63;\n+    let ad: u64 = i64::wrapping_abs(d) as u64;\n+    let t: u64 = two63 + ((d as u64) >> 63);\n+    let anc: u64 = u64::wrapping_sub(t - 1, t % ad);\n+    let mut q1: u64 = two63 / anc;\n+    let mut r1: u64 = two63 - q1 * anc;\n+    let mut q2: u64 = two63 / ad;\n+    let mut r2: u64 = two63 - q2 * ad;\n+    loop {\n+        p = p + 1;\n+        q1 = 2 * q1;\n+        r1 = 2 * r1;\n+        if r1 >= anc {\n+            q1 = q1 + 1;\n+            r1 = r1 - anc;\n+        }\n+        q2 = 2 * q2;\n+        r2 = 2 * r2;\n+        if r2 >= ad {\n+            q2 = q2 + 1;\n+            r2 = r2 - ad;\n+        }\n+        let delta: u64 = ad - r2;\n+        if !(q1 < delta || (q1 == delta && r1 == 0)) {\n+            break;\n+        }\n+    }\n+\n+    MS64 {\n+        mulBy: (if d < 0 {\n+                    u64::wrapping_neg(q2 + 1)\n+                } else {\n+                    q2 + 1\n+                }) as i64,\n+        shiftBy: p - 64,\n+    }\n+}\n+\n+#[cfg(test)]\n+mod tests {\n+    use super::{magicU32, magicU64, magicS32, magicS64};\n+    use super::{MU32, MU64, MS32, MS64};\n+\n+    fn mkMU32(mulBy: u32, doAdd: bool, shiftBy: i32) -> MU32 {\n+        MU32 {\n+            mulBy,\n+            doAdd,\n+            shiftBy,\n+        }\n+    }\n+\n+    fn mkMU64(mulBy: u64, doAdd: bool, shiftBy: i32) -> MU64 {\n+        MU64 {\n+            mulBy,\n+            doAdd,\n+            shiftBy,\n+        }\n+    }\n+\n+    fn mkMS32(mulBy: i32, shiftBy: i32) -> MS32 {\n+        MS32 { mulBy, shiftBy }\n+    }\n+\n+    fn mkMS64(mulBy: i64, shiftBy: i32) -> MS64 {\n+        MS64 { mulBy, shiftBy }\n+    }\n+\n+    #[test]\n+    fn test_magicU32() {\n+        assert_eq!(magicU32(2u32), mkMU32(0x80000000u32, false, 0));\n+        assert_eq!(magicU32(3u32), mkMU32(0xaaaaaaabu32, false, 1));\n+        assert_eq!(magicU32(4u32), mkMU32(0x40000000u32, false, 0));\n+        assert_eq!(magicU32(5u32), mkMU32(0xcccccccdu32, false, 2));\n+        assert_eq!(magicU32(6u32), mkMU32(0xaaaaaaabu32, false, 2));\n+        assert_eq!(magicU32(7u32), mkMU32(0x24924925u32, true, 3));\n+        assert_eq!(magicU32(9u32), mkMU32(0x38e38e39u32, false, 1));\n+        assert_eq!(magicU32(10u32), mkMU32(0xcccccccdu32, false, 3));\n+        assert_eq!(magicU32(11u32), mkMU32(0xba2e8ba3u32, false, 3));\n+        assert_eq!(magicU32(12u32), mkMU32(0xaaaaaaabu32, false, 3));\n+        assert_eq!(magicU32(25u32), mkMU32(0x51eb851fu32, false, 3));\n+        assert_eq!(magicU32(125u32), mkMU32(0x10624dd3u32, false, 3));\n+        assert_eq!(magicU32(625u32), mkMU32(0xd1b71759u32, false, 9));\n+        assert_eq!(magicU32(1337u32), mkMU32(0x88233b2bu32, true, 11));\n+        assert_eq!(magicU32(65535u32), mkMU32(0x80008001u32, false, 15));\n+        assert_eq!(magicU32(65536u32), mkMU32(0x00010000u32, false, 0));\n+        assert_eq!(magicU32(65537u32), mkMU32(0xffff0001u32, false, 16));\n+        assert_eq!(magicU32(31415927u32), mkMU32(0x445b4553u32, false, 23));\n+        assert_eq!(magicU32(0xdeadbeefu32), mkMU32(0x93275ab3u32, false, 31));\n+        assert_eq!(magicU32(0xfffffffdu32), mkMU32(0x40000001u32, false, 30));\n+        assert_eq!(magicU32(0xfffffffeu32), mkMU32(0x00000003u32, true, 32));\n+        assert_eq!(magicU32(0xffffffffu32), mkMU32(0x80000001u32, false, 31));\n+    }\n+    #[test]\n+    fn test_magicU64() {\n+        assert_eq!(magicU64(2u64), mkMU64(0x8000000000000000u64, false, 0));\n+        assert_eq!(magicU64(3u64), mkMU64(0xaaaaaaaaaaaaaaabu64, false, 1));\n+        assert_eq!(magicU64(4u64), mkMU64(0x4000000000000000u64, false, 0));\n+        assert_eq!(magicU64(5u64), mkMU64(0xcccccccccccccccdu64, false, 2));\n+        assert_eq!(magicU64(6u64), mkMU64(0xaaaaaaaaaaaaaaabu64, false, 2));\n+        assert_eq!(magicU64(7u64), mkMU64(0x2492492492492493u64, true, 3));\n+        assert_eq!(magicU64(9u64), mkMU64(0xe38e38e38e38e38fu64, false, 3));\n+        assert_eq!(magicU64(10u64), mkMU64(0xcccccccccccccccdu64, false, 3));\n+        assert_eq!(magicU64(11u64), mkMU64(0x2e8ba2e8ba2e8ba3u64, false, 1));\n+        assert_eq!(magicU64(12u64), mkMU64(0xaaaaaaaaaaaaaaabu64, false, 3));\n+        assert_eq!(magicU64(25u64), mkMU64(0x47ae147ae147ae15u64, true, 5));\n+        assert_eq!(magicU64(125u64), mkMU64(0x0624dd2f1a9fbe77u64, true, 7));\n+        assert_eq!(magicU64(625u64), mkMU64(0x346dc5d63886594bu64, false, 7));\n+        assert_eq!(magicU64(1337u64), mkMU64(0xc4119d952866a139u64, false, 10));\n+        assert_eq!(\n+            magicU64(31415927u64),\n+            mkMU64(0x116d154b9c3d2f85u64, true, 25)\n+        );\n+        assert_eq!(\n+            magicU64(0x00000000deadbeefu64),\n+            mkMU64(0x93275ab2dfc9094bu64, false, 31)\n+        );\n+        assert_eq!(\n+            magicU64(0x00000000fffffffdu64),\n+            mkMU64(0x8000000180000005u64, false, 31)\n+        );\n+        assert_eq!(\n+            magicU64(0x00000000fffffffeu64),\n+            mkMU64(0x0000000200000005u64, true, 32)\n+        );\n+        assert_eq!(\n+            magicU64(0x00000000ffffffffu64),\n+            mkMU64(0x8000000080000001u64, false, 31)\n+        );\n+        assert_eq!(\n+            magicU64(0x0000000100000000u64),\n+            mkMU64(0x0000000100000000u64, false, 0)\n+        );\n+        assert_eq!(\n+            magicU64(0x0000000100000001u64),\n+            mkMU64(0xffffffff00000001u64, false, 32)\n+        );\n+        assert_eq!(\n+            magicU64(0x0ddc0ffeebadf00du64),\n+            mkMU64(0x2788e9d394b77da1u64, true, 60)\n+        );\n+        assert_eq!(\n+            magicU64(0xfffffffffffffffdu64),\n+            mkMU64(0x4000000000000001u64, false, 62)\n+        );\n+        assert_eq!(\n+            magicU64(0xfffffffffffffffeu64),\n+            mkMU64(0x0000000000000003u64, true, 64)\n+        );\n+        assert_eq!(\n+            magicU64(0xffffffffffffffffu64),\n+            mkMU64(0x8000000000000001u64, false, 63)\n+        );\n+    }\n+    #[test]\n+    fn test_magicS32() {\n+        assert_eq!(magicS32(-0x80000000i32), mkMS32(0x7fffffffu32 as i32, 30));\n+        assert_eq!(magicS32(-0x7FFFFFFFi32), mkMS32(0xbfffffffu32 as i32, 29));\n+        assert_eq!(magicS32(-0x7FFFFFFEi32), mkMS32(0x7ffffffdu32 as i32, 30));\n+        assert_eq!(magicS32(-31415927i32), mkMS32(0xbba4baadu32 as i32, 23));\n+        assert_eq!(magicS32(-1337i32), mkMS32(0x9df73135u32 as i32, 9));\n+        assert_eq!(magicS32(-256i32), mkMS32(0x7fffffffu32 as i32, 7));\n+        assert_eq!(magicS32(-5i32), mkMS32(0x99999999u32 as i32, 1));\n+        assert_eq!(magicS32(-3i32), mkMS32(0x55555555u32 as i32, 1));\n+        assert_eq!(magicS32(-2i32), mkMS32(0x7fffffffu32 as i32, 0));\n+        assert_eq!(magicS32(2i32), mkMS32(0x80000001u32 as i32, 0));\n+        assert_eq!(magicS32(3i32), mkMS32(0x55555556u32 as i32, 0));\n+        assert_eq!(magicS32(4i32), mkMS32(0x80000001u32 as i32, 1));\n+        assert_eq!(magicS32(5i32), mkMS32(0x66666667u32 as i32, 1));\n+        assert_eq!(magicS32(6i32), mkMS32(0x2aaaaaabu32 as i32, 0));\n+        assert_eq!(magicS32(7i32), mkMS32(0x92492493u32 as i32, 2));\n+        assert_eq!(magicS32(9i32), mkMS32(0x38e38e39u32 as i32, 1));\n+        assert_eq!(magicS32(10i32), mkMS32(0x66666667u32 as i32, 2));\n+        assert_eq!(magicS32(11i32), mkMS32(0x2e8ba2e9u32 as i32, 1));\n+        assert_eq!(magicS32(12i32), mkMS32(0x2aaaaaabu32 as i32, 1));\n+        assert_eq!(magicS32(25i32), mkMS32(0x51eb851fu32 as i32, 3));\n+        assert_eq!(magicS32(125i32), mkMS32(0x10624dd3u32 as i32, 3));\n+        assert_eq!(magicS32(625i32), mkMS32(0x68db8badu32 as i32, 8));\n+        assert_eq!(magicS32(1337i32), mkMS32(0x6208cecbu32 as i32, 9));\n+        assert_eq!(magicS32(31415927i32), mkMS32(0x445b4553u32 as i32, 23));\n+        assert_eq!(magicS32(0x7ffffffei32), mkMS32(0x80000003u32 as i32, 30));\n+        assert_eq!(magicS32(0x7fffffffi32), mkMS32(0x40000001u32 as i32, 29));\n+    }\n+    #[test]\n+    fn test_magicS64() {\n+        assert_eq!(\n+            magicS64(-0x8000000000000000i64),\n+            mkMS64(0x7fffffffffffffffu64 as i64, 62)\n+        );\n+        assert_eq!(\n+            magicS64(-0x7FFFFFFFFFFFFFFFi64),\n+            mkMS64(0xbfffffffffffffffu64 as i64, 61)\n+        );\n+        assert_eq!(\n+            magicS64(-0x7FFFFFFFFFFFFFFEi64),\n+            mkMS64(0x7ffffffffffffffdu64 as i64, 62)\n+        );\n+        assert_eq!(\n+            magicS64(-0x0ddC0ffeeBadF00di64),\n+            mkMS64(0x6c3b8b1635a4412fu64 as i64, 59)\n+        );\n+        assert_eq!(\n+            magicS64(-0x100000001i64),\n+            mkMS64(0x800000007fffffffu64 as i64, 31)\n+        );\n+        assert_eq!(\n+            magicS64(-0x100000000i64),\n+            mkMS64(0x7fffffffffffffffu64 as i64, 31)\n+        );\n+        assert_eq!(\n+            magicS64(-0xFFFFFFFFi64),\n+            mkMS64(0x7fffffff7fffffffu64 as i64, 31)\n+        );\n+        assert_eq!(\n+            magicS64(-0xFFFFFFFEi64),\n+            mkMS64(0x7ffffffefffffffdu64 as i64, 31)\n+        );\n+        assert_eq!(\n+            magicS64(-0xFFFFFFFDi64),\n+            mkMS64(0x7ffffffe7ffffffbu64 as i64, 31)\n+        );\n+        assert_eq!(\n+            magicS64(-0xDeadBeefi64),\n+            mkMS64(0x6cd8a54d2036f6b5u64 as i64, 31)\n+        );\n+        assert_eq!(\n+            magicS64(-31415927i64),\n+            mkMS64(0x7749755a31e1683du64 as i64, 24)\n+        );\n+        assert_eq!(magicS64(-1337i64), mkMS64(0x9df731356bccaf63u64 as i64, 9));\n+        assert_eq!(magicS64(-256i64), mkMS64(0x7fffffffffffffffu64 as i64, 7));\n+        assert_eq!(magicS64(-5i64), mkMS64(0x9999999999999999u64 as i64, 1));\n+        assert_eq!(magicS64(-3i64), mkMS64(0x5555555555555555u64 as i64, 1));\n+        assert_eq!(magicS64(-2i64), mkMS64(0x7fffffffffffffffu64 as i64, 0));\n+        assert_eq!(magicS64(2i64), mkMS64(0x8000000000000001u64 as i64, 0));\n+        assert_eq!(magicS64(3i64), mkMS64(0x5555555555555556u64 as i64, 0));\n+        assert_eq!(magicS64(4i64), mkMS64(0x8000000000000001u64 as i64, 1));\n+        assert_eq!(magicS64(5i64), mkMS64(0x6666666666666667u64 as i64, 1));\n+        assert_eq!(magicS64(6i64), mkMS64(0x2aaaaaaaaaaaaaabu64 as i64, 0));\n+        assert_eq!(magicS64(7i64), mkMS64(0x4924924924924925u64 as i64, 1));\n+        assert_eq!(magicS64(9i64), mkMS64(0x1c71c71c71c71c72u64 as i64, 0));\n+        assert_eq!(magicS64(10i64), mkMS64(0x6666666666666667u64 as i64, 2));\n+        assert_eq!(magicS64(11i64), mkMS64(0x2e8ba2e8ba2e8ba3u64 as i64, 1));\n+        assert_eq!(magicS64(12i64), mkMS64(0x2aaaaaaaaaaaaaabu64 as i64, 1));\n+        assert_eq!(magicS64(25i64), mkMS64(0xa3d70a3d70a3d70bu64 as i64, 4));\n+        assert_eq!(magicS64(125i64), mkMS64(0x20c49ba5e353f7cfu64 as i64, 4));\n+        assert_eq!(magicS64(625i64), mkMS64(0x346dc5d63886594bu64 as i64, 7));\n+        assert_eq!(magicS64(1337i64), mkMS64(0x6208ceca9433509du64 as i64, 9));\n+        assert_eq!(\n+            magicS64(31415927i64),\n+            mkMS64(0x88b68aa5ce1e97c3u64 as i64, 24)\n+        );\n+        assert_eq!(\n+            magicS64(0x00000000deadbeefi64),\n+            mkMS64(0x93275ab2dfc9094bu64 as i64, 31)\n+        );\n+        assert_eq!(\n+            magicS64(0x00000000fffffffdi64),\n+            mkMS64(0x8000000180000005u64 as i64, 31)\n+        );\n+        assert_eq!(\n+            magicS64(0x00000000fffffffei64),\n+            mkMS64(0x8000000100000003u64 as i64, 31)\n+        );\n+        assert_eq!(\n+            magicS64(0x00000000ffffffffi64),\n+            mkMS64(0x8000000080000001u64 as i64, 31)\n+        );\n+        assert_eq!(\n+            magicS64(0x0000000100000000i64),\n+            mkMS64(0x8000000000000001u64 as i64, 31)\n+        );\n+        assert_eq!(\n+            magicS64(0x0000000100000001i64),\n+            mkMS64(0x7fffffff80000001u64 as i64, 31)\n+        );\n+        assert_eq!(\n+            magicS64(0x0ddc0ffeebadf00di64),\n+            mkMS64(0x93c474e9ca5bbed1u64 as i64, 59)\n+        );\n+        assert_eq!(\n+            magicS64(0x7ffffffffffffffdi64),\n+            mkMS64(0x2000000000000001u64 as i64, 60)\n+        );\n+        assert_eq!(\n+            magicS64(0x7ffffffffffffffei64),\n+            mkMS64(0x8000000000000003u64 as i64, 62)\n+        );\n+        assert_eq!(\n+            magicS64(0x7fffffffffffffffi64),\n+            mkMS64(0x4000000000000001u64 as i64, 61)\n+        );\n+    }\n+    #[test]\n+    fn test_magic_generators_dont_panic() {\n+        // The point of this is to check that the magic number generators\n+        // don't panic with integer wraparounds, especially at boundary\n+        // cases for their arguments.  The actual results are thrown away.\n+        let mut total: u64 = 0;\n+        println!(\"Testing UP magicU32\");\n+        for x in 2..(200 * 1000u32) {\n+            let m = magicU32(x);\n+            total = total ^ (m.mulBy as u64);\n+            total = total + (m.shiftBy as u64);\n+            total = total - (if m.doAdd { 123 } else { 456 });\n+        }\n+        println!(\"Testing DOWN magicU32\");\n+        for x in 0..(200 * 1000u32) {\n+            let m = magicU32(0xFFFF_FFFFu32 - x);\n+            total = total ^ (m.mulBy as u64);\n+            total = total + (m.shiftBy as u64);\n+            total = total - (if m.doAdd { 123 } else { 456 });\n+        }\n+\n+        println!(\"Testing UP magicU64\");\n+        for x in 2..(200 * 1000u64) {\n+            let m = magicU64(x);\n+            total = total ^ (m.mulBy as u64);\n+            total = total + (m.shiftBy as u64);\n+            total = total - (if m.doAdd { 123 } else { 456 });\n+        }\n+        println!(\"Testing DOWN magicU64\");\n+        for x in 0..(200 * 1000u64) {\n+            let m = magicU64(0xFFFF_FFFF_FFFF_FFFFu64 - x);\n+            total = total ^ (m.mulBy as u64);\n+            total = total + (m.shiftBy as u64);\n+            total = total - (if m.doAdd { 123 } else { 456 });\n+        }\n+\n+        println!(\"Testing UP magicS32\");\n+        for x in 0..(200 * 1000i32) {\n+            let m = magicS32(-0x8000_0000i32 + x);\n+            total = total ^ (m.mulBy as u64);\n+            total = total + (m.shiftBy as u64);\n+        }\n+        println!(\"Testing DOWN magicS32\");\n+        for x in 0..(200 * 1000i32) {\n+            let m = magicS32(0x7FFF_FFFFi32 - x);\n+            total = total ^ (m.mulBy as u64);\n+            total = total + (m.shiftBy as u64);\n+        }\n+\n+        println!(\"Testing UP magicS64\");\n+        for x in 0..(200 * 1000i64) {\n+            let m = magicS64(-0x8000_0000_0000_0000i64 + x);\n+            total = total ^ (m.mulBy as u64);\n+            total = total + (m.shiftBy as u64);\n+        }\n+        println!(\"Testing DOWN magicS64\");\n+        for x in 0..(200 * 1000i64) {\n+            let m = magicS64(0x7FFF_FFFF_FFFF_FFFFi64 - x);\n+            total = total ^ (m.mulBy as u64);\n+            total = total + (m.shiftBy as u64);\n+        }\n+        // Force |total| -- and hence, the entire computation -- to\n+        // be used, so that rustc can't optimise it out.\n+        assert_eq!(total, 7547519887532559585u64);\n+    }\n+}\n+\n+\n+//----------------------------------------------------------------------\n+//\n+// Pattern-match helpers and transformation for div and rem by constants.\n+\n+#[derive(Debug)]\n+enum DivRemByConstInfo {\n+    DivU32(Value, u32), // In all cases, the arguments are:\n+    DivU64(Value, u64), // left operand, right operand\n+    DivS32(Value, i32),\n+    DivS64(Value, i64),\n+    RemU32(Value, u32),\n+    RemU64(Value, u64),\n+    RemS32(Value, i32),\n+    RemS64(Value, i64),\n+}\n+\n+// Possibly create a DivRemByConstInfo from the given components, by\n+// figuring out which, if any, of the 8 cases apply, and also taking care to\n+// sanity-check the immediate.\n+fn package_up_divrem_info(\n+    argL: Value,\n+    argL_ty: Type,\n+    argRs: i64,\n+    isSigned: bool,\n+    isRem: bool,\n+) -> Option<DivRemByConstInfo> {\n+    let argRu: u64 = argRs as u64;\n+    if !isSigned && argL_ty == I32 && argRu < 0x1_0000_0000 {\n+        let con = if isRem {\n+            DivRemByConstInfo::RemU32\n+        } else {\n+            DivRemByConstInfo::DivU32\n+        };\n+        return Some(con(argL, argRu as u32));\n+    }\n+    if !isSigned && argL_ty == I64 {\n+        // unsigned 64, no range constraint\n+        let con = if isRem {\n+            DivRemByConstInfo::RemU64\n+        } else {\n+            DivRemByConstInfo::DivU64\n+        };\n+        return Some(con(argL, argRu));\n+    }\n+    if isSigned && argL_ty == I32 && (argRu <= 0x7fff_ffff || argRu >= 0xffff_ffff_8000_0000) {\n+        let con = if isRem {\n+            DivRemByConstInfo::RemS32\n+        } else {\n+            DivRemByConstInfo::DivS32\n+        };\n+        return Some(con(argL, argRu as i32));\n+    }\n+    if isSigned && argL_ty == I64 {\n+        // signed 64, no range constraint\n+        let con = if isRem {\n+            DivRemByConstInfo::RemS64\n+        } else {\n+            DivRemByConstInfo::DivS64\n+        };\n+        return Some(con(argL, argRu as i64));\n+    }\n+    None\n+}\n+\n+// Examine |idata| to see if it is a div or rem by a constant, and if so\n+// return the operands, signedness, operation size and div-vs-rem-ness in a\n+// handy bundle.\n+fn get_div_info(inst: Inst, dfg: &DataFlowGraph) -> Option<DivRemByConstInfo> {\n+    let idata: &InstructionData = &dfg[inst];\n+\n+    if let &InstructionData::BinaryImm { opcode, arg, imm } = idata {\n+        let (isSigned, isRem) = match opcode {\n+            Opcode::UdivImm => (false, false),\n+            Opcode::UremImm => (false, true),\n+            Opcode::SdivImm => (true, false),\n+            Opcode::SremImm => (true, true),\n+            _other => return None,\n+        };\n+        // Pull the operation size (type) from the left arg\n+        let argL_ty = dfg.value_type(arg);\n+        return package_up_divrem_info(arg, argL_ty, imm.into(), isSigned, isRem);\n+    }\n+\n+    if let &InstructionData::Binary { opcode, args } = idata {\n+        let (isSigned, isRem) = match opcode {\n+            Opcode::Udiv => (false, false),\n+            Opcode::Urem => (false, true),\n+            Opcode::Sdiv => (true, false),\n+            Opcode::Srem => (true, true),\n+            _other => return None,\n+        };\n+        let argR: Value = args[1];\n+        if let Some(simm64) = get_const(argR, dfg) {\n+            let argL: Value = args[0];\n+            // Pull the operation size (type) from the left arg\n+            let argL_ty = dfg.value_type(argL);\n+            return package_up_divrem_info(argL, argL_ty, simm64, isSigned, isRem);\n+        }\n+    }\n+\n+    None\n+}\n+\n+// Actually do the transformation given a bundle containing the relevant\n+// information.  |divrem_info| describes a div or rem by a constant, that\n+// |pos| currently points at, and |inst| is the associated instruction.\n+// |inst| is replaced by a sequence of other operations that calculate the\n+// same result.  Note that there are various |divrem_info| cases where we\n+// cannot do any transformation, in which case |inst| is left unchanged.\n+fn do_divrem_transformation(divrem_info: &DivRemByConstInfo, pos: &mut FuncCursor, inst: Inst) {\n+    let isRem = match *divrem_info {\n+        DivRemByConstInfo::DivU32(_, _) |\n+        DivRemByConstInfo::DivU64(_, _) |\n+        DivRemByConstInfo::DivS32(_, _) |\n+        DivRemByConstInfo::DivS64(_, _) => false,\n+        DivRemByConstInfo::RemU32(_, _) |\n+        DivRemByConstInfo::RemU64(_, _) |\n+        DivRemByConstInfo::RemS32(_, _) |\n+        DivRemByConstInfo::RemS64(_, _) => true,\n+    };\n+\n+    match divrem_info {\n+\n+        // -------------------- U32 --------------------\n+\n+        // U32 div, rem by zero: ignore\n+        &DivRemByConstInfo::DivU32(_n1, 0) |\n+        &DivRemByConstInfo::RemU32(_n1, 0) => {}\n+\n+        // U32 div by 1: identity\n+        // U32 rem by 1: zero\n+        &DivRemByConstInfo::DivU32(n1, 1) |\n+        &DivRemByConstInfo::RemU32(n1, 1) => {\n+            if isRem {\n+                pos.func.dfg.replace(inst).iconst(I32, 0);\n+            } else {\n+                pos.func.dfg.replace(inst).copy(n1);\n+            }\n+        }\n+\n+        // U32 div, rem by a power-of-2\n+        &DivRemByConstInfo::DivU32(n1, d) |\n+        &DivRemByConstInfo::RemU32(n1, d) if d.count_ones() == 1 => {\n+            assert!(d >= 2);\n+            // compute k where d == 2^k\n+            let k = d.trailing_zeros();\n+            assert!(k >= 1 && k <= 31);\n+            if isRem {\n+                let mask = (1u64 << k) - 1;\n+                pos.func.dfg.replace(inst).band_imm(n1, mask as i64);\n+            } else {\n+                pos.func.dfg.replace(inst).ushr_imm(n1, k as i64);\n+            }\n+        }\n+\n+        // U32 div, rem by non-power-of-2\n+        &DivRemByConstInfo::DivU32(n1, d) |\n+        &DivRemByConstInfo::RemU32(n1, d) => {\n+            assert!(d >= 3);\n+            let MU32 {\n+                mulBy,\n+                doAdd,\n+                shiftBy,\n+            } = magicU32(d);\n+            let qf; // final quotient\n+            let q0 = pos.ins().iconst(I32, mulBy as i64);\n+            let q1 = pos.ins().umulhi(n1, q0);\n+            if doAdd {\n+                assert!(shiftBy >= 1 && shiftBy <= 32);\n+                let t1 = pos.ins().isub(n1, q1);\n+                let t2 = pos.ins().ushr_imm(t1, 1);\n+                let t3 = pos.ins().iadd(t2, q1);\n+                // I never found any case where shiftBy == 1 here.\n+                // So there's no attempt to fold out a zero shift.\n+                qf = pos.ins().ushr_imm(t3, (shiftBy - 1) as i64);\n+            } else {\n+                assert!(shiftBy >= 0 && shiftBy <= 31);\n+                // Whereas shiftBy == 0 has been observed here.\n+                if shiftBy > 0 {\n+                    qf = pos.ins().ushr_imm(q1, shiftBy as i64);\n+                } else {\n+                    qf = q1;\n+                }\n+            }\n+            // Now qf holds the final quotient.  If necessary calculate the\n+            // remainder instead.\n+            if isRem {\n+                let tt = pos.ins().imul_imm(qf, d as i64);\n+                pos.func.dfg.replace(inst).isub(n1, tt);\n+            } else {\n+                pos.func.dfg.replace(inst).copy(qf);\n+            }\n+        }\n+\n+        // -------------------- U64 --------------------\n+\n+        // U64 div, rem by zero: ignore\n+        &DivRemByConstInfo::DivU64(_n1, 0) |\n+        &DivRemByConstInfo::RemU64(_n1, 0) => {}\n+\n+        // U64 div by 1: identity\n+        // U64 rem by 1: zero\n+        &DivRemByConstInfo::DivU64(n1, 1) |\n+        &DivRemByConstInfo::RemU64(n1, 1) => {\n+            if isRem {\n+                pos.func.dfg.replace(inst).iconst(I64, 0);\n+            } else {\n+                pos.func.dfg.replace(inst).copy(n1);\n+            }\n+        }\n+\n+        // U64 div, rem by a power-of-2\n+        &DivRemByConstInfo::DivU64(n1, d) |\n+        &DivRemByConstInfo::RemU64(n1, d) if d.count_ones() == 1 => {","path":"lib/cretonne/src/preopt.rs","position":797,"original_position":797,"commit_id":"e0ed4f2c9bf3e6454b5373a4d299c67344a7f637","original_commit_id":"e0ed4f2c9bf3e6454b5373a4d299c67344a7f637","user":{"login":"sunfishcode","id":4503403,"avatar_url":"https://avatars1.githubusercontent.com/u/4503403?v=4","gravatar_id":"","url":"https://api.github.com/users/sunfishcode","html_url":"https://github.com/sunfishcode","followers_url":"https://api.github.com/users/sunfishcode/followers","following_url":"https://api.github.com/users/sunfishcode/following{/other_user}","gists_url":"https://api.github.com/users/sunfishcode/gists{/gist_id}","starred_url":"https://api.github.com/users/sunfishcode/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sunfishcode/subscriptions","organizations_url":"https://api.github.com/users/sunfishcode/orgs","repos_url":"https://api.github.com/users/sunfishcode/repos","events_url":"https://api.github.com/users/sunfishcode/events{/privacy}","received_events_url":"https://api.github.com/users/sunfishcode/received_events","type":"User","site_admin":false},"body":"Rust has a `.is_power_of_two()` which can do this.","created_at":"2018-02-26T19:36:36Z","updated_at":"2018-02-26T19:53:18Z","html_url":"https://github.com/Cretonne/cretonne/pull/249#discussion_r170709971","pull_request_url":"https://api.github.com/repos/Cretonne/cretonne/pulls/249","author_association":"COLLABORATOR","_links":{"self":{"href":"https://api.github.com/repos/Cretonne/cretonne/pulls/comments/170709971"},"html":{"href":"https://github.com/Cretonne/cretonne/pull/249#discussion_r170709971"},"pull_request":{"href":"https://api.github.com/repos/Cretonne/cretonne/pulls/249"}}},"pull_request":{"url":"https://api.github.com/repos/Cretonne/cretonne/pulls/249","id":171187227,"html_url":"https://github.com/Cretonne/cretonne/pull/249","diff_url":"https://github.com/Cretonne/cretonne/pull/249.diff","patch_url":"https://github.com/Cretonne/cretonne/pull/249.patch","issue_url":"https://api.github.com/repos/Cretonne/cretonne/issues/249","number":249,"state":"open","locked":false,"title":"Adds support to transform integer div and rem by constants into cheap…","user":{"login":"julian-seward1","id":17145426,"avatar_url":"https://avatars2.githubusercontent.com/u/17145426?v=4","gravatar_id":"","url":"https://api.github.com/users/julian-seward1","html_url":"https://github.com/julian-seward1","followers_url":"https://api.github.com/users/julian-seward1/followers","following_url":"https://api.github.com/users/julian-seward1/following{/other_user}","gists_url":"https://api.github.com/users/julian-seward1/gists{/gist_id}","starred_url":"https://api.github.com/users/julian-seward1/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/julian-seward1/subscriptions","organizations_url":"https://api.github.com/users/julian-seward1/orgs","repos_url":"https://api.github.com/users/julian-seward1/repos","events_url":"https://api.github.com/users/julian-seward1/events{/privacy}","received_events_url":"https://api.github.com/users/julian-seward1/received_events","type":"User","site_admin":false},"body":"…er equivalents.\r\n\r\nAdds support for transforming integer division and remainder by constants\r\ninto sequences that do not involve division instructions.\r\n\r\n* div/rem by constant powers of two are turned into right shifts, plus some\r\n  fixups for the signed cases.\r\n\r\n* div/rem by constant non-powers of two are turned into double length\r\n  multiplies by a magic constant, plus some fixups involving shifts,\r\n  addition and subtraction, that depends on the constant, the word size and\r\n  the signedness involved.\r\n\r\n* The following cases are transformed: div and rem, signed or unsigned, 32\r\n  or 64 bit.  The only un-transformed cases are: unsigned div and rem by\r\n  zero, signed div and rem by zero or -1.\r\n\r\n* This is all incorporated within a new transformation pass, \"preopt\", in\r\n  lib/cretonne/src/preopt.rs.\r\n\r\n* In preopt.rs, fn do_preopt() is the main driver.  It is designed to be\r\n  extensible to transformations of other kinds of instructions.  Currently\r\n  it merely uses a helper to identify div/rem transformation candidates and\r\n  another helper to perform the transformation.\r\n\r\n* In preopt.rs, fn get_div_info() pattern matches to find candidates, both\r\n  cases where the second arg is an immediate, and cases where the second\r\n  arg is an identifier bound to an immediate at its definition point.\r\n\r\n* In preopt.rs, fn do_divrem_transformation() does the heavy lifting of the\r\n  transformation proper.  It in turn uses magic{S,U}{32,64} to calculate the\r\n  magic numbers required for the transformations.\r\n\r\n* There are many test cases for the transformation proper:\r\n    filetests/preopt/div_by_const_non_power_of_2.cton\r\n    filetests/preopt/div_by_const_power_of_2.cton\r\n    filetests/preopt/rem_by_const_non_power_of_2.cton\r\n    filetests/preopt/rem_by_const_power_of_2.cton\r\n    filetests/preopt/div_by_const_indirect.cton\r\n  preopt.rs also contains a set of tests for magic number generation.\r\n\r\n* The main (non-power-of-2) transformation requires instructions that return\r\n  the high word of a double-length multiply.  For this, instructions umulhi\r\n  and smulhi have been added to the core instruction set.  These will map\r\n  directly to single instructions on most non-intel targets.\r\n\r\n* intel does not have an instruction exactly like that.  For intel,\r\n  instructions x86_umulx and x86_smulx have been added.  These map to real\r\n  instructions and return both result words.  The intel legaliser will\r\n  rewrite {s,u}mulhi into x86_{s,u}mulx uses that throw away the lower half\r\n  word.  Tests:\r\n    filetests/isa/intel/legalize-mulhi.cton (new file)\r\n    filetests/isa/intel/binary64.cton (added x86_{s,u}mulx encoding tests)","created_at":"2018-02-24T17:04:29Z","updated_at":"2018-02-26T19:53:18Z","closed_at":null,"merged_at":null,"merge_commit_sha":"2f23535cafce7491e3200d7c546fdfa3b1a8ac81","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/Cretonne/cretonne/pulls/249/commits","review_comments_url":"https://api.github.com/repos/Cretonne/cretonne/pulls/249/comments","review_comment_url":"https://api.github.com/repos/Cretonne/cretonne/pulls/comments{/number}","comments_url":"https://api.github.com/repos/Cretonne/cretonne/issues/249/comments","statuses_url":"https://api.github.com/repos/Cretonne/cretonne/statuses/e0ed4f2c9bf3e6454b5373a4d299c67344a7f637","head":{"label":"julian-seward1:master","ref":"master","sha":"e0ed4f2c9bf3e6454b5373a4d299c67344a7f637","user":{"login":"julian-seward1","id":17145426,"avatar_url":"https://avatars2.githubusercontent.com/u/17145426?v=4","gravatar_id":"","url":"https://api.github.com/users/julian-seward1","html_url":"https://github.com/julian-seward1","followers_url":"https://api.github.com/users/julian-seward1/followers","following_url":"https://api.github.com/users/julian-seward1/following{/other_user}","gists_url":"https://api.github.com/users/julian-seward1/gists{/gist_id}","starred_url":"https://api.github.com/users/julian-seward1/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/julian-seward1/subscriptions","organizations_url":"https://api.github.com/users/julian-seward1/orgs","repos_url":"https://api.github.com/users/julian-seward1/repos","events_url":"https://api.github.com/users/julian-seward1/events{/privacy}","received_events_url":"https://api.github.com/users/julian-seward1/received_events","type":"User","site_admin":false},"repo":{"id":119867683,"name":"cretonne","full_name":"julian-seward1/cretonne","owner":{"login":"julian-seward1","id":17145426,"avatar_url":"https://avatars2.githubusercontent.com/u/17145426?v=4","gravatar_id":"","url":"https://api.github.com/users/julian-seward1","html_url":"https://github.com/julian-seward1","followers_url":"https://api.github.com/users/julian-seward1/followers","following_url":"https://api.github.com/users/julian-seward1/following{/other_user}","gists_url":"https://api.github.com/users/julian-seward1/gists{/gist_id}","starred_url":"https://api.github.com/users/julian-seward1/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/julian-seward1/subscriptions","organizations_url":"https://api.github.com/users/julian-seward1/orgs","repos_url":"https://api.github.com/users/julian-seward1/repos","events_url":"https://api.github.com/users/julian-seward1/events{/privacy}","received_events_url":"https://api.github.com/users/julian-seward1/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/julian-seward1/cretonne","description":"Cretonne code generator","fork":true,"url":"https://api.github.com/repos/julian-seward1/cretonne","forks_url":"https://api.github.com/repos/julian-seward1/cretonne/forks","keys_url":"https://api.github.com/repos/julian-seward1/cretonne/keys{/key_id}","collaborators_url":"https://api.github.com/repos/julian-seward1/cretonne/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/julian-seward1/cretonne/teams","hooks_url":"https://api.github.com/repos/julian-seward1/cretonne/hooks","issue_events_url":"https://api.github.com/repos/julian-seward1/cretonne/issues/events{/number}","events_url":"https://api.github.com/repos/julian-seward1/cretonne/events","assignees_url":"https://api.github.com/repos/julian-seward1/cretonne/assignees{/user}","branches_url":"https://api.github.com/repos/julian-seward1/cretonne/branches{/branch}","tags_url":"https://api.github.com/repos/julian-seward1/cretonne/tags","blobs_url":"https://api.github.com/repos/julian-seward1/cretonne/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/julian-seward1/cretonne/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/julian-seward1/cretonne/git/refs{/sha}","trees_url":"https://api.github.com/repos/julian-seward1/cretonne/git/trees{/sha}","statuses_url":"https://api.github.com/repos/julian-seward1/cretonne/statuses/{sha}","languages_url":"https://api.github.com/repos/julian-seward1/cretonne/languages","stargazers_url":"https://api.github.com/repos/julian-seward1/cretonne/stargazers","contributors_url":"https://api.github.com/repos/julian-seward1/cretonne/contributors","subscribers_url":"https://api.github.com/repos/julian-seward1/cretonne/subscribers","subscription_url":"https://api.github.com/repos/julian-seward1/cretonne/subscription","commits_url":"https://api.github.com/repos/julian-seward1/cretonne/commits{/sha}","git_commits_url":"https://api.github.com/repos/julian-seward1/cretonne/git/commits{/sha}","comments_url":"https://api.github.com/repos/julian-seward1/cretonne/comments{/number}","issue_comment_url":"https://api.github.com/repos/julian-seward1/cretonne/issues/comments{/number}","contents_url":"https://api.github.com/repos/julian-seward1/cretonne/contents/{+path}","compare_url":"https://api.github.com/repos/julian-seward1/cretonne/compare/{base}...{head}","merges_url":"https://api.github.com/repos/julian-seward1/cretonne/merges","archive_url":"https://api.github.com/repos/julian-seward1/cretonne/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/julian-seward1/cretonne/downloads","issues_url":"https://api.github.com/repos/julian-seward1/cretonne/issues{/number}","pulls_url":"https://api.github.com/repos/julian-seward1/cretonne/pulls{/number}","milestones_url":"https://api.github.com/repos/julian-seward1/cretonne/milestones{/number}","notifications_url":"https://api.github.com/repos/julian-seward1/cretonne/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/julian-seward1/cretonne/labels{/name}","releases_url":"https://api.github.com/repos/julian-seward1/cretonne/releases{/id}","deployments_url":"https://api.github.com/repos/julian-seward1/cretonne/deployments","created_at":"2018-02-01T17:13:19Z","updated_at":"2018-02-01T17:13:22Z","pushed_at":"2018-02-24T16:59:53Z","git_url":"git://github.com/julian-seward1/cretonne.git","ssh_url":"git@github.com:julian-seward1/cretonne.git","clone_url":"https://github.com/julian-seward1/cretonne.git","svn_url":"https://github.com/julian-seward1/cretonne","homepage":null,"size":4214,"stargazers_count":0,"watchers_count":0,"language":"Rust","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":null,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"Cretonne:master","ref":"master","sha":"4c317f7326010a2f642571f5ce91ea9fbd7c7668","user":{"login":"Cretonne","id":11573910,"avatar_url":"https://avatars3.githubusercontent.com/u/11573910?v=4","gravatar_id":"","url":"https://api.github.com/users/Cretonne","html_url":"https://github.com/Cretonne","followers_url":"https://api.github.com/users/Cretonne/followers","following_url":"https://api.github.com/users/Cretonne/following{/other_user}","gists_url":"https://api.github.com/users/Cretonne/gists{/gist_id}","starred_url":"https://api.github.com/users/Cretonne/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Cretonne/subscriptions","organizations_url":"https://api.github.com/users/Cretonne/orgs","repos_url":"https://api.github.com/users/Cretonne/repos","events_url":"https://api.github.com/users/Cretonne/events{/privacy}","received_events_url":"https://api.github.com/users/Cretonne/received_events","type":"Organization","site_admin":false},"repo":{"id":50268165,"name":"cretonne","full_name":"Cretonne/cretonne","owner":{"login":"Cretonne","id":11573910,"avatar_url":"https://avatars3.githubusercontent.com/u/11573910?v=4","gravatar_id":"","url":"https://api.github.com/users/Cretonne","html_url":"https://github.com/Cretonne","followers_url":"https://api.github.com/users/Cretonne/followers","following_url":"https://api.github.com/users/Cretonne/following{/other_user}","gists_url":"https://api.github.com/users/Cretonne/gists{/gist_id}","starred_url":"https://api.github.com/users/Cretonne/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Cretonne/subscriptions","organizations_url":"https://api.github.com/users/Cretonne/orgs","repos_url":"https://api.github.com/users/Cretonne/repos","events_url":"https://api.github.com/users/Cretonne/events{/privacy}","received_events_url":"https://api.github.com/users/Cretonne/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/Cretonne/cretonne","description":"Cretonne code generator","fork":false,"url":"https://api.github.com/repos/Cretonne/cretonne","forks_url":"https://api.github.com/repos/Cretonne/cretonne/forks","keys_url":"https://api.github.com/repos/Cretonne/cretonne/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Cretonne/cretonne/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Cretonne/cretonne/teams","hooks_url":"https://api.github.com/repos/Cretonne/cretonne/hooks","issue_events_url":"https://api.github.com/repos/Cretonne/cretonne/issues/events{/number}","events_url":"https://api.github.com/repos/Cretonne/cretonne/events","assignees_url":"https://api.github.com/repos/Cretonne/cretonne/assignees{/user}","branches_url":"https://api.github.com/repos/Cretonne/cretonne/branches{/branch}","tags_url":"https://api.github.com/repos/Cretonne/cretonne/tags","blobs_url":"https://api.github.com/repos/Cretonne/cretonne/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Cretonne/cretonne/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Cretonne/cretonne/git/refs{/sha}","trees_url":"https://api.github.com/repos/Cretonne/cretonne/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Cretonne/cretonne/statuses/{sha}","languages_url":"https://api.github.com/repos/Cretonne/cretonne/languages","stargazers_url":"https://api.github.com/repos/Cretonne/cretonne/stargazers","contributors_url":"https://api.github.com/repos/Cretonne/cretonne/contributors","subscribers_url":"https://api.github.com/repos/Cretonne/cretonne/subscribers","subscription_url":"https://api.github.com/repos/Cretonne/cretonne/subscription","commits_url":"https://api.github.com/repos/Cretonne/cretonne/commits{/sha}","git_commits_url":"https://api.github.com/repos/Cretonne/cretonne/git/commits{/sha}","comments_url":"https://api.github.com/repos/Cretonne/cretonne/comments{/number}","issue_comment_url":"https://api.github.com/repos/Cretonne/cretonne/issues/comments{/number}","contents_url":"https://api.github.com/repos/Cretonne/cretonne/contents/{+path}","compare_url":"https://api.github.com/repos/Cretonne/cretonne/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Cretonne/cretonne/merges","archive_url":"https://api.github.com/repos/Cretonne/cretonne/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Cretonne/cretonne/downloads","issues_url":"https://api.github.com/repos/Cretonne/cretonne/issues{/number}","pulls_url":"https://api.github.com/repos/Cretonne/cretonne/pulls{/number}","milestones_url":"https://api.github.com/repos/Cretonne/cretonne/milestones{/number}","notifications_url":"https://api.github.com/repos/Cretonne/cretonne/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Cretonne/cretonne/labels{/name}","releases_url":"https://api.github.com/repos/Cretonne/cretonne/releases{/id}","deployments_url":"https://api.github.com/repos/Cretonne/cretonne/deployments","created_at":"2016-01-24T02:04:11Z","updated_at":"2018-02-26T13:11:10Z","pushed_at":"2018-02-24T17:04:29Z","git_url":"git://github.com/Cretonne/cretonne.git","ssh_url":"git@github.com:Cretonne/cretonne.git","clone_url":"https://github.com/Cretonne/cretonne.git","svn_url":"https://github.com/Cretonne/cretonne","homepage":null,"size":4225,"stargazers_count":510,"watchers_count":510,"language":"Rust","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":45,"mirror_url":null,"archived":false,"open_issues_count":36,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0"},"forks":45,"open_issues":36,"watchers":510,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/Cretonne/cretonne/pulls/249"},"html":{"href":"https://github.com/Cretonne/cretonne/pull/249"},"issue":{"href":"https://api.github.com/repos/Cretonne/cretonne/issues/249"},"comments":{"href":"https://api.github.com/repos/Cretonne/cretonne/issues/249/comments"},"review_comments":{"href":"https://api.github.com/repos/Cretonne/cretonne/pulls/249/comments"},"review_comment":{"href":"https://api.github.com/repos/Cretonne/cretonne/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/Cretonne/cretonne/pulls/249/commits"},"statuses":{"href":"https://api.github.com/repos/Cretonne/cretonne/statuses/e0ed4f2c9bf3e6454b5373a4d299c67344a7f637"}},"author_association":"CONTRIBUTOR"}}
{"actor":{"display_login":"sunfishcode"}}