1// optimize TCG using extract op
2//
3// Copyright: (C) 2017 Philippe Mathieu-Daudé. GPLv2+.
4// Confidence: High
5// Options: --macro-file scripts/cocci-macro-file.h
6//
7// Nikunj A Dadhania optimization:
8// http://lists.nongnu.org/archive/html/qemu-devel/2017-02/msg05211.html
9// Aurelien Jarno optimization:
10// http://lists.nongnu.org/archive/html/qemu-devel/2017-05/msg01466.html
11//
12// This script can be run either using spatch locally or via a docker image:
13//
14// $ spatch \
15//     --macro-file scripts/cocci-macro-file.h \
16//     --sp-file scripts/coccinelle/tcg_gen_extract.cocci \
17//     --keep-comments --in-place \
18//     --use-gitgrep --dir target
19//
20// $ docker run --rm -v `pwd`:`pwd` -w `pwd` philmd/coccinelle \
21//     --macro-file scripts/cocci-macro-file.h \
22//     --sp-file scripts/coccinelle/tcg_gen_extract.cocci \
23//     --keep-comments --in-place \
24//     --use-gitgrep --dir target
25
26@initialize:python@
27@@
28import sys
29fd = sys.stderr
30def debug(msg="", trailer="\n"):
31    fd.write("[DBG] " + msg + trailer)
32def low_bits_count(value):
33    bits_count = 0
34    while (value & (1 << bits_count)):
35        bits_count += 1
36    return bits_count
37def Mn(order): # Mersenne number
38    return (1 << order) - 1
39
40@match@
41identifier ret;
42metavariable arg;
43constant ofs, msk;
44position shr_p, and_p;
45@@
46(
47    tcg_gen_shri_i32@shr_p
48|
49    tcg_gen_shri_i64@shr_p
50|
51    tcg_gen_shri_tl@shr_p
52)(ret, arg, ofs);
53...  WHEN != ret
54(
55    tcg_gen_andi_i32@and_p
56|
57    tcg_gen_andi_i64@and_p
58|
59    tcg_gen_andi_tl@and_p
60)(ret, ret, msk);
61
62@script:python verify_len depends on match@
63ret_s << match.ret;
64msk_s << match.msk;
65shr_p << match.shr_p;
66extract_len;
67@@
68is_optimizable = False
69debug("candidate at %s:%s" % (shr_p[0].file, shr_p[0].line))
70try: # only eval integer, no #define like 'SR_M' (cpp did this, else some headers are missing).
71    msk_v = long(msk_s.strip("UL"), 0)
72    msk_b = low_bits_count(msk_v)
73    if msk_b == 0:
74        debug("  value: 0x%x low_bits: %d" % (msk_v, msk_b))
75    else:
76        debug("  value: 0x%x low_bits: %d [Mersenne number: 0x%x]" % (msk_v, msk_b, Mn(msk_b)))
77        is_optimizable = Mn(msk_b) == msk_v # check low_bits
78        coccinelle.extract_len = "%d" % msk_b
79    debug("  candidate %s optimizable" % ("IS" if is_optimizable else "is NOT"))
80except:
81    debug("  ERROR (check included headers?)")
82cocci.include_match(is_optimizable)
83debug()
84
85@replacement depends on verify_len@
86identifier match.ret;
87metavariable match.arg;
88constant match.ofs, match.msk;
89position match.shr_p, match.and_p;
90identifier verify_len.extract_len;
91@@
92(
93-tcg_gen_shri_i32@shr_p(ret, arg, ofs);
94+tcg_gen_extract_i32(ret, arg, ofs, extract_len);
95...  WHEN != ret
96-tcg_gen_andi_i32@and_p(ret, ret, msk);
97|
98-tcg_gen_shri_i64@shr_p(ret, arg, ofs);
99+tcg_gen_extract_i64(ret, arg, ofs, extract_len);
100...  WHEN != ret
101-tcg_gen_andi_i64@and_p(ret, ret, msk);
102|
103-tcg_gen_shri_tl@shr_p(ret, arg, ofs);
104+tcg_gen_extract_tl(ret, arg, ofs, extract_len);
105...  WHEN != ret
106-tcg_gen_andi_tl@and_p(ret, ret, msk);
107)
108