1 #![feature(core_intrinsics)]
2 //static TEST_FUNC_NAME: &'static [u8; 7] = b"main()\0";
3 static TEST_FUNC_NAME: &'static [u8; 6] = b"main()";
9 unsafe { core::intrinsics::instrprof_increment(TEST_FUNC_NAME as *const u8, 1234 as u64, 3 as u32, 0 as u32) };
14 unsafe { core::intrinsics::instrprof_increment(TEST_FUNC_NAME as *const u8, 1234 as u64, 3 as u32, 1 as u32) };
23 I NEED TO INSERT THE instrprof_increment() CALL:
25 1. JUST BEFORE THE switchInt(_4) (because we haven't counted entering the function main() yet, deferring that to "JUST BEFORE FIRST BRANCH")
26 2. SOME TIME AFTER THE switchInt(_4), AND JUST BEFORE ANOTHER BRANCH (in this case, before "goto")
27 2.a. NOT BEFORE BOTH GOTO'S AFTER switchInt(_4) (because one can be calculated by counter expression), BUT PERHAPS INSERT A noop PLACEHOLDER
28 AS A MARKER TO INCLUDE THE COVERAGE REGION AND REFERENCE THE COUNTERS TO BE SUBTRACTED (AND/OR SUMMED)?
30 WHY DEFER INSERTING COUNTERS TO "JUST BEFORE FIRST BRANCH"? We can ignore panic/unwind() and only count if the coverage region ACTUALLY
31 executed in entirety. BUT IS THAT NECESSARY? IS IT MUCH EASIER TO INSERT COUNTERS AT THE TOP OF A REGION THAT MUST EXECUTE IN ENTIRETY IF
32 PANIC DOES NOT OCCUR? AND WHAT IF WE ADD SUPPORT FOR PANIC UNWIND (later)?
34 IS THERE A BENEFIT OF THE DEFERRED APPROACH WHEN CONSIDERING EXPRESSIONS MAY HAVE EARLY RETURNS? (BECAUSE, WE STILL NEED TO COUNT THE REGION
35 LEADING UP TO THE EXPRESSION ANYWAY)
37 =================================================
38 =================================================
40 To inject an intrinsic after computing a final expression value of a coverage region:
42 Replace the following basic block end (last statement plus terminator):
44 ... <statements to compute _4> ...
50 _4 = Lt(move _5, move _6)
53 <------ to insert instrprof_increment() here
54 FakeRead(ForMatchedPlace, _4)
55 --------------------------------------------------------------------------------------
59 =================================================
60 Insert call to intrinsic with:
62 StorageLive(_4) # _4 is now meant for deferred FakeRead(ForMatchdPlace, _4) in BasicBlock after increment() call
63 StorageLive(_5) # Unchanged except _4 is now _5
64 StorageLive(_6) # Unchanged except _5 is now _6
65 _6 = _1 # Unchanged except _5 is now _6
66 StorageLive(_7) # Unchanged except _6 is now _7
67 _7 = _2 # Unchanged except _6 is now _7
68 _5 = Lt(move _6, move _7) # Unchanged except _4, _5, _6 is now _5, _6, _7
69 StorageDead(_7) # Unchanged except _6 is now _7
70 StorageDead(_6) # Unchanged except _5 is now _6
72 FakeRead(ForLet, _5) # CHANGED ForMatchedPlace to ForLet
74 > # ALL NEW AND NECESSARY TO CALL instrprof_increment()
75 > StorageLive(_8) # ?? stores function pointer to instrprof_increment function?
79 > _11 = const {alloc1+0: &&[u8; 6]}
80 > _10 = &raw const (*(*_11))
81 > _9 = move _10 as *const u8 (Pointer(ArrayToPointer))
89 > --------------------------------------------------------------------------------------
90 > _8 = const std::intrinsics::instrprof_increment(move _9, move _12, move _13, move _14)
101 _4 = _5 # ARE THESE LINES REDUNDANT? CAN I JUST PASS _5 DIRECTLY TO FakeRead()?
102 StorageDead(_5) # DROP "_t" temp result of `let _t = a < b`
103 # (NOTE THAT IF SO, I CAN REMOVE _5 altogether, and use _4, which coincidentally makes less changes)
106 FakeRead(ForMatchedPlace, _4) # Unchanged
107 --------------------------------------------------------------------------------------
108 switchInt(_4) # Unchanged
111 =================================================
112 Can I skip the extra variable and insert call to intrinsic with:
114 StorageLive(_4) # Unchanged
115 StorageLive(_5) # Unchanged
117 StorageLive(_6) # Unchanged
119 _4 = Lt(move _5, move _6) # Unchanged
120 StorageDead(_6) # Unchanged
121 StorageDead(_5) # Unchanged
123 > # ALL NEW AND NECESSARY TO CALL instrprof_increment()
124 > FakeRead(ForLet, _4) # Save the post-increment result in temp "_t"
125 > StorageLive(_8) # ?? stores function pointer to instrprof_increment function?
129 > _11 = const {alloc1+0: &&[u8; 6]}
130 > _10 = &raw const (*(*_11))
131 > _9 = move _10 as *const u8 (Pointer(ArrayToPointer))
134 > _12 = const 1234u64
139 > --------------------------------------------------------------------------------------
140 > _8 = const std::intrinsics::instrprof_increment(move _9, move _12, move _13, move _14)
151 FakeRead(ForMatchedPlace, _4) # Unchanged (PREVIOUSLY USED IN FakeRead(ForLet), is that OK?)
152 --------------------------------------------------------------------------------------
153 switchInt(_4) # Unchanged
159 =================================================
160 =================================================
162 For the second inserted call to instrprof_increment, without that call we have:
164 --------------------------------------------------------------------------------------
165 switchInt(_4) # From above
167 -> otherwise # that is, "NOT false"
170 <------ to insert instrprof_increment() here
171 --------------------------------------------------------------------------------------
174 -> # No label. No condition, and not a "return"
176 FakeRead(ForLet, _3) # NOTE: Unused result
182 --------------------------------------------------------------------------------------
185 -> # No label. No condition, and not a "return"
190 =================================================
191 With the call to increment():
193 --------------------------------------------------------------------------------------
194 switchInt(_4) # From above
196 -> otherwise # "NOT false" # UNCHANGED
198 StorageLive(_15) # CHANGED! Allocated new storage (_15) for the result of match, if true.
199 _15 = const true # UNCHANGED except _3 is now _15
200 FakeRead(ForLet, _15) # CHANGED! Assign value to temporary (to be assigned to _3 later) ... Do I need to do this?
202 > # ALL NEW AND NECESSARY TO CALL instrprof_increment()
203 > StorageLive(_16) # pointer to instrprof_increment() function ?
207 > _19 = const {alloc1+0: &&[u8; 6]}
208 > _18 = &raw const (*(*_19))
209 > _17 = move _18 as *const u8 (Pointer(ArrayToPointer))
212 > _20 = const 1234u64
217 > --------------------------------------------------------------------------------------
218 > _16 = const std::intrinsics::instrprof_increment(move _17, move _20, move _21, move _22)
231 --------------------------------# UNCHANGED-------------------------------------------
236 FakeRead(ForLet, _3) # UNCHANGED
237 StorageDead(_4) # UNCHANGED
239 StorageDead(_3) # UNCHANGED
240 StorageDead(_2) # UNCHANGED
241 StorageDead(_1) # UNCHANGED
242 --------------------------------------------------------------------------------------
247 return # from main() # UNCHANGED
249 =================================================
250 As before, can I skip the extra variable (_15) and insert the call to intrinsic with _3 directly?:
253 --------------------------------------------------------------------------------------
254 switchInt(_4) # From above
256 -> otherwise # "NOT false" # UNCHANGED
258 _3 = const true # UNCHANGED?
260 > # ALL NEW AND NECESSARY TO CALL instrprof_increment()
261 > StorageLive(_16) # pointer to instrprof_increment() function ?
265 > _19 = const {alloc1+0: &&[u8; 6]}
266 > _18 = &raw const (*(*_19))
267 > _17 = move _18 as *const u8 (Pointer(ArrayToPointer))
270 > _20 = const 1234u64
275 > --------------------------------------------------------------------------------------
276 > _16 = const std::intrinsics::instrprof_increment(move _17, move _20, move _21, move _22)
287 --------------------------------# UNCHANGED-------------------------------------------
292 FakeRead(ForLet, _3) # UNCHANGED
293 StorageDead(_4) # UNCHANGED
295 StorageDead(_3) # UNCHANGED
296 StorageDead(_2) # UNCHANGED
297 StorageDead(_1) # UNCHANGED
298 --------------------------------------------------------------------------------------
303 return # from main() # UNCHANGED