open Core_kernel
open Bap.Std
open OUnit2

open Powerpc_tests_helpers

let andi_dot arch ctxt =
  let bytes = "\x71\x2a\x00\x1F" in  (** andi.   r10,r9,31 *)
  let r10 = find_gpr arch "R10" in
  let r9 = find_gpr arch "R9" in
  let width = arch_width arch in
  let init = Bil.[
      r9 := int (Word.of_int ~width 10);
    ] in
  let expected = Word.of_int ~width 10 in
  check_gpr init bytes r10 expected arch ctxt

let andis_dot arch ctxt =
  let bytes = "\x75\x2a\x0E\x00" in  (** andis.  r10,r9,2048 *)
  let r10 = find_gpr arch "R10" in
  let r9 = find_gpr arch "R9" in
  let width = arch_width arch in
  let value = Word.of_int ~width 0x0800_0000 in
  let init = Bil.[
      r9 := int value;
    ] in
  let expected = value in
  check_gpr init bytes r10 expected arch ctxt

let and_ arch ctxt =
  let bytes = "\x7f\x39\xe8\x38" in (** and r25 r25 r29 *)
  let r25 = find_gpr arch "R25" in
  let r29 = find_gpr arch "R29" in
  let width = arch_width arch in
  let x = 31 in
  let y = 10 in
  let r = x land y in
  let init = Bil.[
      r29  := int (Word.of_int ~width x);
      r25 := int (Word.of_int ~width y);
    ] in
  let expected = Word.of_int ~width r in
  check_gpr init bytes r25 expected arch ctxt

let and_dot arch ctxt =
  let bytes = "\x7f\x39\xe8\x39" in (** and. r25 r25 r29 *)
  let r25 = find_gpr arch "R25" in
  let r29 = find_gpr arch "R29" in
  let width = arch_width arch in
  let x = 31 in
  let y = 10 in
  let r = x land y in
  let init = Bil.[
      r29  := int (Word.of_int ~width x);
      r25 := int (Word.of_int ~width y);
    ] in
  let ctxt = eval init bytes arch in
  let r25_value = lookup_var ctxt r25 in
  let expected = Word.of_int ~width r in
  let nf_value = lookup_var ctxt nf in
  let pf_value = lookup_var ctxt pf in
  let zf_value = lookup_var ctxt zf in
  assert_bool "add. failed" (is_equal_words expected r25_value);
  assert_bool "addc. failed" (is_equal_words Word.b0 nf_value);
  assert_bool "addc. failed" (is_equal_words Word.b1 pf_value);
  assert_bool "addc. failed" (is_equal_words Word.b0 zf_value)

let andc arch ctxt =
  let bytes = "\x7c\xea\x50\x78" in (** andc r10 r7 r10 *)
  let r10 = find_gpr arch "R10" in
  let r7  = find_gpr arch "R7" in
  let width = arch_width arch in
  let x = 21 in
  let y = 10 in
  let r = x land (lnot y) in
  let init = Bil.[
      r7 := int (Word.of_int ~width x);
      r10 := int (Word.of_int ~width y);
    ] in
  let expected = Word.of_int ~width r in
  check_gpr init bytes r10 expected arch ctxt

let andc_dot arch ctxt =
  let bytes = "\x7c\xea\x50\x79" in (** andc. r10 r7 r10 *)
  let r10 = find_gpr arch "R10" in
  let r7  = find_gpr arch "R7" in
  let width = arch_width arch in
  let x = 42 in
  let y = x in
  let r = x land (lnot y) in
  let init = Bil.[
      r7 := int (Word.of_int ~width x);
      r10 := int (Word.of_int ~width y);
    ] in
  let ctxt = eval init bytes arch in
  let r10_value = lookup_var ctxt r10 in
  let expected = Word.of_int ~width r in
  let nf_value = lookup_var ctxt nf in
  let pf_value = lookup_var ctxt pf in
  let zf_value = lookup_var ctxt zf in
  assert_bool "addc. failed" (is_equal_words expected r10_value);
  assert_bool "addc. failed" (is_equal_words Word.b0 nf_value);
  assert_bool "addc. failed" (is_equal_words Word.b0 pf_value);
  assert_bool "addc. failed" (is_equal_words Word.b1 zf_value)

let ori arch ctxt =
  let bytes = "\x60\xc6\x51\xc1" in  (** ori     r6,r6,20929 *)
  let r6 = find_gpr arch "R6" in
  let width = arch_width arch in
  let x = 62 in
  let r = x lor 20929 in
  let init = Bil.[
      r6 := int (Word.of_int ~width x);
    ] in
  let expected = Word.of_int ~width r in
  check_gpr init bytes r6 expected arch ctxt

let oris arch ctxt =
  let bytes = "\x65\x4a\x00\x0F" in (** oris    r10,r10,15  *)
  let r10 = find_gpr arch "R10" in
  let width = arch_width arch in
  let x = 61440 in
  let y = 15 in
  let r = x lxor (y lsl 16) in
  let init = Bil.[
      r10 := int (Word.of_int ~width x);
    ] in
  let expected = Word.of_int ~width r in
  check_gpr init bytes r10 expected arch ctxt

let or_  arch ctxt =
  let bytes = "\x7f\x38\xc3\x78" in (** or r24,r25,r24  *)
  let r24 = find_gpr arch "R24" in
  let r25 = find_gpr arch "R25" in
  let width = arch_width arch in
  let x = 24 in
  let y = 10 in
  let r = x lor y in
  let init = Bil.[
      r24 := int (Word.of_int ~width x);
      r25 := int (Word.of_int ~width y);
    ] in
  let expected = Word.of_int ~width r in
  check_gpr init bytes r24 expected arch ctxt

let or_dot arch ctxt =
  let bytes = "\x7f\x38\xc3\x79" in (** or r24,r25,r24  *)
  let r24 = find_gpr arch "R24" in
  let r25 = find_gpr arch "R25" in
  let width = arch_width arch in
  let x = 24 in
  let y = 10 in
  let r = x lor y in
  let init = Bil.[
      r24 := int (Word.of_int ~width x);
      r25 := int (Word.of_int ~width y);
    ] in
  let ctxt = eval init bytes arch in
  let r24_value = lookup_var ctxt r24 in
  let expected = Word.of_int ~width r in
  let nf_value = lookup_var ctxt nf in
  let pf_value = lookup_var ctxt pf in
  let zf_value = lookup_var ctxt zf in
  assert_bool "or. failed" (is_equal_words expected r24_value);
  assert_bool "or. failed" (is_equal_words Word.b0 nf_value);
  assert_bool "or. failed" (is_equal_words Word.b1 pf_value);
  assert_bool "or. failed" (is_equal_words Word.b0 zf_value)

let orc arch ctxt =
  let bytes = "\x7c\x8a\x53\x38" in (** orc     r10,r4,r10 *)
  let r4 = find_gpr arch "R4" in
  let r10 = find_gpr arch "R10" in
  let width = arch_width arch in
  let x = 42 in
  let y = 10 in
  let r = x lor (lnot y)  in
  let init = Bil.[
      r4 := int (Word.of_int ~width x);
      r10 := int (Word.of_int ~width y);
    ] in
  let expected = Word.of_int ~width r in
  check_gpr init bytes r10 expected arch ctxt

let orc_dot arch ctxt =
  let bytes = "\x7c\x8a\x53\x39" in (** orc.     r10,r4,r10 *)
  let r4 = find_gpr arch "R4" in
  let r10 = find_gpr arch "R10" in
  let width = arch_width arch in
  let x = 42 in
  let y = 0 in
  let r = x lor (lnot y)  in
  let init = Bil.[
      r4 := int (Word.of_int ~width x);
      r10 := int (Word.of_int ~width y);
    ] in
  let ctxt = eval init bytes arch in
  let r10_value = lookup_var ctxt r10 in
  let expected = Word.of_int ~width r in
  let nf_value = lookup_var ctxt nf in
  let pf_value = lookup_var ctxt pf in
  let zf_value = lookup_var ctxt zf in
  assert_bool "orc. failed" (is_equal_words expected r10_value);
  assert_bool "orc. failed" (is_equal_words Word.b1 nf_value);
  assert_bool "orc. failed" (is_equal_words Word.b0 pf_value);
  assert_bool "orc. failed" (is_equal_words Word.b0 zf_value)

let xori arch ctxt =
  let bytes = "\x68\x63\x00\x0B" in (** xori    r3,r3,11   *)
  let r3 = find_gpr arch "R3" in
  let width = arch_width arch in
  let x = 16 in
  let r = x lxor 11 in
  let init = Bil.[
      r3 := int (Word.of_int ~width x);
    ] in
  let expected = Word.of_int ~width r in
  check_gpr init bytes r3 expected arch ctxt

let xoris arch ctxt =
  let bytes = "\x6d\x2a\x00\x0f" in (** xoris r10,r9,15 *)
  let r9 = find_gpr arch "R9" in
  let r10 = find_gpr arch "R10" in
  let width = arch_width arch in
  let x = 0x1F0000 in
  let r = x lxor (15 lsl 16) in
  let init = Bil.[
      r9 := int (Word.of_int ~width x);
    ] in
  let expected = Word.of_int ~width r in
  check_gpr init bytes r10 expected arch ctxt

let xor_ arch ctxt =
  let bytes = "\x7c\x6a\x52\x78" in (** xor     r10,r3,r10 *)
  let r3 = find_gpr arch "R3" in
  let r10 = find_gpr arch "R10" in
  let width = arch_width arch in
  let x = 42 in
  let y = 15 in
  let r = x lxor y in
  let init = Bil.[
      r3 := int (Word.of_int ~width x);
      r10 := int (Word.of_int ~width y);
    ] in
  let expected = Word.of_int ~width r in
  check_gpr init bytes r10 expected arch ctxt

let xor_dot arch ctxt =
  let bytes = "\x7c\x6a\x52\x79" in (** xor.     r10,r3,r10 *)
  let r3 = find_gpr arch "R3" in
  let r10 = find_gpr arch "R10" in
  let width = arch_width arch in
  let x = 42 in
  let y = 42 in
  let r = x lxor y in
  let init = Bil.[
      r3 := int (Word.of_int ~width x);
      r10 := int (Word.of_int ~width y);
    ] in
  let ctxt = eval init bytes arch in
  let r10_value = lookup_var ctxt r10 in
  let expected = Word.of_int ~width r in
  let nf_value = lookup_var ctxt nf in
  let pf_value = lookup_var ctxt pf in
  let zf_value = lookup_var ctxt zf in
  assert_bool "xor. failed" (is_equal_words expected r10_value);
  assert_bool "xor. failed" (is_equal_words Word.b0 nf_value);
  assert_bool "xor. failed" (is_equal_words Word.b0 pf_value);
  assert_bool "xor. failed" (is_equal_words Word.b1 zf_value)

let nand arch ctxt =
  let bytes = "\x7c\x63\x23\xb8" in (** nand    r3,r3,r4 *)
  let r3 = find_gpr arch "R3" in
  let r4 = find_gpr arch "R4" in
  let width = arch_width arch in
  let x = 42 in
  let y = 15 in
  let r = lnot (x land y) in
  let init = Bil.[
      r3 := int (Word.of_int ~width x);
      r4 := int (Word.of_int ~width y);
    ] in
  let expected = Word.of_int ~width r in
  check_gpr init bytes r3 expected arch ctxt

let nand_dot arch ctxt =
  let bytes = "\x7c\x63\x23\xb9" in (** nand.    r3,r3,r4 *)
  let r3 = find_gpr arch "R3" in
  let r4 = find_gpr arch "R4" in
  let width = arch_width arch in
  let x = 42 in
  let y = 15 in
  let r = lnot (x land y) in
  let init = Bil.[
      r3 := int (Word.of_int ~width x);
      r4 := int (Word.of_int ~width y);
    ] in
  let ctxt = eval init bytes arch in
  let r3_value = lookup_var ctxt r3 in
  let expected = Word.of_int ~width r in
  let nf_value = lookup_var ctxt nf in
  let pf_value = lookup_var ctxt pf in
  let zf_value = lookup_var ctxt zf in
  assert_bool "nand. failed" (is_equal_words expected r3_value);
  assert_bool "nand. failed" (is_equal_words Word.b1 nf_value);
  assert_bool "nand. failed" (is_equal_words Word.b0 pf_value);
  assert_bool "nand. failed" (is_equal_words Word.b0 zf_value)

let nor arch ctxt =
  let bytes = "\x7d\x09\x48\xf8" in (** nor     r9,r8,r9 *)
  let r8 = find_gpr arch "R8" in
  let r9 = find_gpr arch "R9" in
  let width = arch_width arch in
  let x = 42 in
  let y = 15 in
  let r = lnot (x lor y) in
  let init = Bil.[
      r8 := int (Word.of_int ~width x);
      r9 := int (Word.of_int ~width y);
    ] in
  let expected = Word.of_int ~width r in
  check_gpr init bytes r9 expected arch ctxt

let nor_dot arch ctxt =
  let bytes = "\x7d\x09\x48\xf9" in (** nor.     r9,r8,r9 *)
  let r8 = find_gpr arch "R8" in
  let r9 = find_gpr arch "R9" in
  let width = arch_width arch in
  let x = 42 in
  let y = -15 in
  let r = lnot (x lor y) in
  let init = Bil.[
      r8 := int (Word.of_int ~width x);
      r9 := int (Word.of_int ~width y);
    ] in
  let ctxt = eval init bytes arch in
  let r9_value = lookup_var ctxt r9 in
  let expected = Word.of_int ~width r in
  let nf_value = lookup_var ctxt nf in
  let pf_value = lookup_var ctxt pf in
  let zf_value = lookup_var ctxt zf in
  assert_bool "nor. failed" (is_equal_words expected r9_value);
  assert_bool "nor. failed" (is_equal_words Word.b0 nf_value);
  assert_bool "nor. failed" (is_equal_words Word.b1 pf_value);
  assert_bool "nor. failed" (is_equal_words Word.b0 zf_value)

let eqv arch ctxt =
  let bytes = "\x7d\x09\x4a\x38" in (** eqv     r9,r8,r9 *)
  let r8 = find_gpr arch "R8" in
  let r9 = find_gpr arch "R9" in
  let width = arch_width arch in
  let x = 42 in
  let y = 15 in
  let r = lnot (x lxor y); in
  let init = Bil.[
      r8 := int (Word.of_int ~width x);
      r9 := int (Word.of_int ~width y);
    ] in
  let expected = Word.of_int ~width r in
  check_gpr init bytes r9 expected arch ctxt

let eqv_dot arch ctxt =
  let bytes = "\x7d\x09\x4a\x39" in (** eqv.     r9,r8,r9 *)
  let r8 = find_gpr arch "R8" in
  let r9 = find_gpr arch "R9" in
  let width = arch_width arch in
  let x = -1 in
  let y = 0 in
  let r = lnot (x lxor y); in
  let init = Bil.[
      r8 := int (Word.of_int ~width x);
      r9 := int (Word.of_int ~width y);
    ] in
  let ctxt = eval init bytes arch in
  let r9_value = lookup_var ctxt r9 in
  let expected = Word.of_int ~width r in
  let nf_value = lookup_var ctxt nf in
  let pf_value = lookup_var ctxt pf in
  let zf_value = lookup_var ctxt zf in
  assert_bool "eqv. failed" (is_equal_words expected r9_value);
  assert_bool "eqv. failed" (is_equal_words Word.b0 nf_value);
  assert_bool "eqv. failed" (is_equal_words Word.b0 pf_value);
  assert_bool "eqv. failed" (is_equal_words Word.b1 zf_value)

let extsb arch ctxt =
  let bytes = "\x7d\x6a\x07\x74" in   (** extsb   r10,r11  *)
  let r10 = find_gpr arch "R10" in
  let r11 = find_gpr arch "R11" in
  let width = arch_width arch in
  let init = Bil.[
      r11 := int (Word.of_int ~width 0xC0);
    ] in
  let expected = Word.of_int64 ~width 0xFFFFFFFFFFFFFFC0L in
  check_gpr init bytes r10 expected arch ctxt

let extsh arch ctxt =
  let bytes = "\x7d\x25\x07\x34" in   (** extsh   r5,r9 *)
  let r5 = find_gpr arch "R5" in
  let r9 = find_gpr arch "R9" in
  let width = arch_width arch in
  let init = Bil.[
      r9 := int (Word.of_int ~width 0xC000);
    ] in
  let expected = Word.of_int64 ~width 0xFFFFFFFFFFFFC000L in
  check_gpr init bytes r5 expected arch ctxt

let exts_dot arch ctxt =
  let bytes = "\x7d\x25\x07\x35" in   (** extsh.   r5,r9 *)
  let r5 = find_gpr arch "R5" in
  let r9 = find_gpr arch "R9" in
  let width = arch_width arch in
  let init = Bil.[
      r9 := int (Word.of_int ~width 0xC000);
    ] in
  let expected = Word.of_int64 ~width 0xFFFFFFFFFFFFC000L in
  let ctxt = eval init bytes arch in
  let r5_value = lookup_var ctxt r5 in
  let nf_value = lookup_var ctxt nf in
  let pf_value = lookup_var ctxt pf in
  let zf_value = lookup_var ctxt zf in
  assert_bool "extsh. failed" (is_equal_words expected r5_value);
  assert_bool "extsh. failed" (is_equal_words Word.b1 nf_value);
  assert_bool "extsh. failed" (is_equal_words Word.b0 pf_value);
  assert_bool "extsh. failed" (is_equal_words Word.b0 zf_value)

let extsw arch ctxt =
  let bytes = "\x7d\x25\x07\xb4" in   (** extsw   r5,r9 *)
  let r5 = find_gpr arch "R5" in
  let r9 = find_gpr arch "R9" in
  let width = arch_width arch in
  let init = Bil.[
      r9 := int (Word.of_int ~width 0xC0000000);
    ] in
  let expected = Word.of_int64 ~width 0xFFFFFFFFC0000000L in
  check_gpr init bytes r5 expected arch ctxt

let extsw_dot arch ctxt =
  let bytes = "\x7d\x25\x07\xb5" in   (** extsw.  r5,r9 *)
  let r5 = find_gpr arch "R5" in
  let r9 = find_gpr arch "R9" in
  let width = arch_width arch in
  let init = Bil.[
      r9 := int (Word.of_int ~width 0xC0000000);
    ] in
  let expected = Word.of_int64 ~width 0xFFFFFFFFC0000000L in
  check_gpr init bytes r5 expected arch ctxt

let cntlzw arch value zeros ctxt =
  let bytes = "\x7c\x63\x00\x34" in
  let r = find_gpr arch "R3" in
  let width = arch_width arch in
  let init = Bil.[
      r := int (Word.of_int ~width value);
    ] in
  let expected = Word.of_int ~width zeros in
  check_gpr init bytes r expected arch ctxt

let cnttzw arch value zeros ctxt =
  let bytes = "\x7c\x63\x04\x34" in
  let r = find_gpr arch "R3" in
  let width = arch_width arch in
  let init = Bil.[
      r := int (Word.of_int ~width value);
    ] in
  let expected = Word.of_int ~width zeros in
  check_gpr init bytes r expected arch ctxt

let cntlzd ctxt =
  let arch = `ppc64 in
  let bytes = "\x7c\x63\x00\x74" in
  let r = find_gpr arch "R3" in
  let width = arch_width arch in
  let value = Word.of_int64 0x0000FFFF_00000000L in
  let init = Bil.[
      r := int value;
    ] in
  let expected = Word.of_int ~width 16 in
  check_gpr init bytes r expected arch ctxt

let cnttzd ctxt =
  let arch = `ppc64 in
  let bytes = "\x7c\x63\x04\x75" in
  let r = find_gpr arch "R3" in
  let width = arch_width arch in
  let value = Word.of_int64 0x00000000_FFFF0000L in
  let init = Bil.[
      r := int value;
    ] in
  let expected = Word.of_int ~width 16 in
  check_gpr init bytes r expected arch ctxt

let cmpb arch ~bytes_cnt x y expected ctxt =
  let bytes = "\x7c\x8a\x53\xf8" in
  let width = arch_width arch in
  let x = Word.of_int ~width x in
  let y = Word.of_int ~width y in
  let r10 = find_gpr arch "R10" in
  let r4 = find_gpr arch "R4" in
  let init = Bil.[
      r10 := int x;
      r4  := int y;
    ] in
  let head = Word.ones (width - bytes_cnt * 8) in
  let expected = Word.of_int ~width:(bytes_cnt * 8) expected in
  let expected = Word.concat head expected in
  check_gpr init bytes r10 expected arch ctxt

let popcntw arch ctxt =
  let bytes = "\x7c\x44\x02\xf4" in (** popcntw r4, r2 *)
  let r4 = find_gpr arch "R4" in
  let r2 = find_gpr arch "R2" in
  let width = arch_width arch in
  let value,expected = match arch with
    | `ppc ->
      Word.of_int64 ~width 0x10000001L,
      Word.of_int64 ~width 0x000000002L
    | _ ->
      Word.of_int64 0xA0200040_10000001L,
      Word.of_int64 0x400000002L in (** 4 bits set in first word, and 2 in second  *)
  let init = Bil.[
      r2 := int value;
    ] in
  check_gpr init bytes r4 expected arch ctxt

let popcntd ctxt =
  let arch = `ppc64 in
  let bytes = "\x7c\x44\x03\xf4" in (** popcntw r4, r2 *)
  let r4 = find_gpr arch "R4" in
  let r2 = find_gpr arch "R2" in
  let width = arch_width arch in
  let value = Word.of_int64 0x0F00000F_00000001L in
  let expected = Word.of_int ~width 9 in
  let init = Bil.[
      r2 := int value;
    ] in
  check_gpr init bytes r4 expected arch ctxt

let bperm ctxt =
  let arch = `ppc64 in
  let bytes = "\x7c\xa1\x49\xf8" in (** bpermd r1, r5, r9  *)
  let r1 = find_gpr arch "R1" in
  let r5 = find_gpr arch "R5" in
  let r9 = find_gpr arch "R9" in
  let width = arch_width arch in
  let index_bits = Word.of_int64 0x05_00_01_44_25_1B_02_04L in
  let value = Word.of_int64 0xFFABCDEF0A0B0C0DL in
  let expected = Word.of_int ~width 0xe3 in
  let init = Bil.[
      r5 := int index_bits;
      r9 := int value;
    ] in
  check_gpr init bytes r1 expected arch ctxt

let suite = "logical" >::: [
    "andi.32"     >:: andi_dot `ppc;
    "andis.32"    >:: andis_dot `ppc;
    "and32"       >:: and_ `ppc;
    "and.32"      >:: and_dot `ppc;
    "andc32"      >:: andc `ppc;
    "andc.32"     >:: andc_dot `ppc;
    "ori32"       >:: ori `ppc;
    "oris32"      >:: oris `ppc;
    "or32"        >:: or_ `ppc;
    "or.32"       >:: or_dot `ppc;
    "orc32"       >:: orc `ppc;
    "orc.32"      >:: orc_dot `ppc;
    "xori32"      >:: xori `ppc;
    "xoris23"     >:: xoris `ppc;
    "xor32"       >:: xor_ `ppc;
    "xor.32"      >:: xor_dot `ppc;
    "nand32"      >:: nand `ppc;
    "nand.32"     >:: nand_dot `ppc;
    "nor32"       >:: nor `ppc;
    "nor.32"      >:: nor_dot `ppc;
    "eqv32"       >:: eqv `ppc;
    "eqv.32"      >:: eqv_dot `ppc;
    "extsb32"     >:: extsb `ppc;
    "extsh32"     >:: extsh `ppc;
    "extsw32"     >:: extsw `ppc;
    "exts.32"     >:: exts_dot `ppc;
    "cntlzw32: 1" >:: cntlzw `ppc 0x0 32;
    "cntlzw32: 2" >:: cntlzw `ppc 0x4000000 5;
    "cntlzw32: 3" >:: cntlzw `ppc 0x40000000 1;
    "cntlzw32: 4" >:: cntlzw `ppc 0x80000000 0;
    "cnttzw32: 1" >:: cnttzw `ppc 0x0 32;
    "cnttzw32: 2" >:: cnttzw `ppc 0x1 0;
    "cnttzw32: 3" >:: cnttzw `ppc 0x2 1;
    "cnttzw32: 4" >:: cnttzw `ppc 0x20 5;
    "cmpb32: 0"   >:: cmpb `ppc ~bytes_cnt:3 0x31_41_AD 0x34_42_AD 0x00_00_FF;
    "cmpb32: 1"   >:: cmpb `ppc ~bytes_cnt:3 0x31_42_45 0x34_42_AD 0x00_FF_00;
    "cmpb32: 2"   >:: cmpb `ppc ~bytes_cnt:3 0 0x34_42_AD 0x0;
    "cmpb32: 3"   >:: cmpb `ppc ~bytes_cnt:3 0x34_42_AD 0x34_42_AD 0xFF_FF_FF;
    "popcntw32"   >:: popcntw `ppc;

    "andi.64"     >:: andi_dot `ppc64;
    "andis.64"    >:: andis_dot `ppc64;
    "and64"       >:: and_ `ppc64;
    "and.64"      >:: and_dot `ppc64;
    "andc64"      >:: andc `ppc64;
    "andc.64"     >:: andc_dot `ppc64;
    "ori64"       >:: ori `ppc64;
    "oris64"      >:: oris `ppc64;
    "or64"        >:: or_ `ppc64;
    "or.64"       >:: or_dot `ppc64;
    "orc64"       >:: orc `ppc64;
    "orc.64"      >:: orc_dot `ppc64;
    "xori64"      >:: xori `ppc64;
    "xoris64"     >:: xoris `ppc64;
    "xor64"       >:: xor_ `ppc64;
    "xor.64"      >:: xor_dot `ppc64;
    "nand64"      >:: nand `ppc64;
    "nand.64"     >:: nand_dot `ppc64;
    "nor64"       >:: nor `ppc64;
    "nor.64"      >:: nor_dot `ppc64;
    "eqv64"       >:: eqv `ppc64;
    "eqv.64"      >:: eqv_dot `ppc64;
    "extsb64"     >:: extsb `ppc64;
    "extsh64"     >:: extsh `ppc64;
    "extsw64"     >:: extsw `ppc64;
    "exts.64"     >:: exts_dot `ppc64;
    "cntlz64: 1"  >:: cntlzw `ppc64 0x0 32;
    "cntlz64: 2"  >:: cntlzw `ppc64 0x4000000 5;
    "cntlz64: 3"  >:: cntlzw `ppc64 0x40000000 1;
    "cntlz64: 4"  >:: cntlzw `ppc64 0x80000000 0;
    "cnttz64: 1"  >:: cnttzw `ppc64 0x0 32;
    "cnttz64: 2"  >:: cnttzw `ppc64 0x1 0;
    "cnttz64: 3"  >:: cnttzw `ppc64 0x2 1;
    "cnttz64: 4"  >:: cnttzw `ppc64 0x20 5;
    "cntlzd"      >:: cntlzd;
    "cnttzd"      >:: cnttzd;
    "cmpb64: 1"   >:: cmpb `ppc64 ~bytes_cnt:3 0x31_42_45 0x34_42_AD 0x00_FF_00;
    "cmpb64: 2"   >:: cmpb `ppc64 ~bytes_cnt:3 0 0x34_42_AD 0x0;
    "cmpb64: 3"   >:: cmpb `ppc64 ~bytes_cnt:3 0x34_42_AD 0x34_42_AD 0xFF_FF_FF;
    "popcntw64"   >:: popcntw `ppc64;
    "popcntd"     >:: popcntd;
    "bperm64"     >:: bperm;
  ]
