Skip to content
← Back

src/ir/values/hash_combine.ghul

1
namespace IR.Values is
2
use System.Reflection.Metadata.ILOpCode
3
4
use Semantic.Types.Type
5
6
use Ghul.Pipes
7
8
// The whole body of a synthesized `get_hash_code`: each member's
9
// hash, folded together.
10
//
11
// Every operand arrives boxed, so a member of any kind answers -
12
// a value type through its box, a bare type parameter through its
13
// own hash, and an absent optional through the null arm rather
14
// than a call that would throw on it.
15
//
16
// ldc.i4.0
17
// <operand> // for each, in declaration order
18
// dup
19
// brfalse <null>
20
// callvirt GetHashCode
21
// br <combine>
22
// <null>:
23
// pop
24
// ldc.i4.0
25
// <combine>:
26
// ... // swap-free: the running total is under
27
// add // the member hash, so mul it beforehand
28
class HASH_COMBINE: Value is
29
operands: Collections.LIST[Value]
30
get_hash_code: Semantic.Symbols.Function
31
// What the fold starts from: a base's own hash where this type
32
// extends one that holds members, so that the members it does
33
// not declare are hashed where they are compared. Zero
34
// otherwise - `object`'s hash is identity, and two equal
35
// values would answer differently through it.
36
seed: Value?
37
_result_type: Type
38
39
type: Type => _result_type
40
is_lightweight_pure: bool => false
41
42
init(
43
operands: Collections.LIST[Value],
44
get_hash_code: Semantic.Symbols.Function,
45
seed: Value?,
46
result_type: Type
47
) is
48
super.init()
49
50
self.operands = operands
51
self.get_hash_code = get_hash_code
52
self.seed = seed
53
self._result_type = result_type
54
si
55
56
gen(context: IR.CONTEXT) is
57
let body = context.current_srm_body_emitter!
58
59
if let s = seed then
60
gen(s, context)
61
else
62
body.ldc_i4(0)
63
fi
64
65
for operand in operands do
66
// Running total first, multiplied before the member's
67
// hash is computed, so the two are in the order `add`
68
// wants and nothing has to be swapped.
69
body.ldc_i4(31)
70
body.op(ILOpCode.MUL)
71
72
let null_label = IR.LABEL()
73
let combine_label = IR.LABEL()
74
75
gen(operand, context)
76
body.op(ILOpCode.DUP)
77
body.branch(ILOpCode.BRFALSE, null_label)
78
body.call_virtual(context.resolve_call_target(get_hash_code))
79
body.branch(ILOpCode.BR, combine_label)
80
81
body.mark_label(null_label)
82
body.op(ILOpCode.POP)
83
body.ldc_i4(0)
84
85
body.mark_label(combine_label)
86
body.op(ILOpCode.ADD)
87
od
88
si
89
90
to_string() -> string =>
91
"hash-combine:[{type}]({operands |> map(o => "{o}") |> join(",")})"
92
si
93
si