annotate llvm/docs/HistoricalNotes/2001-02-09-AdveCommentsResponse.txt @ 150:1d019706d866

LLVM10
author anatofuz
date Thu, 13 Feb 2020 15:10:13 +0900
parents
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
150
anatofuz
parents:
diff changeset
1 From: Chris Lattner <sabre@nondot.org>
anatofuz
parents:
diff changeset
2 To: "Vikram S. Adve" <vadve@cs.uiuc.edu>
anatofuz
parents:
diff changeset
3 Subject: Re: LLVM Feedback
anatofuz
parents:
diff changeset
4
anatofuz
parents:
diff changeset
5 I've included your feedback in the /home/vadve/lattner/llvm/docs directory
anatofuz
parents:
diff changeset
6 so that it will live in CVS eventually with the rest of LLVM. I've
anatofuz
parents:
diff changeset
7 significantly updated the documentation to reflect the changes you
anatofuz
parents:
diff changeset
8 suggested, as specified below:
anatofuz
parents:
diff changeset
9
anatofuz
parents:
diff changeset
10 > We should consider eliminating the type annotation in cases where it is
anatofuz
parents:
diff changeset
11 > essentially obvious from the instruction type:
anatofuz
parents:
diff changeset
12 > br bool <cond>, label <iftrue>, label <iffalse>
anatofuz
parents:
diff changeset
13 > I think your point was that making all types explicit improves clarity
anatofuz
parents:
diff changeset
14 > and readability. I agree to some extent, but it also comes at the
anatofuz
parents:
diff changeset
15 > cost of verbosity. And when the types are obvious from people's
anatofuz
parents:
diff changeset
16 > experience (e.g., in the br instruction), it doesn't seem to help as
anatofuz
parents:
diff changeset
17 > much.
anatofuz
parents:
diff changeset
18
anatofuz
parents:
diff changeset
19 Very true. We should discuss this more, but my reasoning is more of a
anatofuz
parents:
diff changeset
20 consistency argument. There are VERY few instructions that can have all
anatofuz
parents:
diff changeset
21 of the types eliminated, and doing so when available unnecessarily makes
anatofuz
parents:
diff changeset
22 the language more difficult to handle. Especially when you see 'int
anatofuz
parents:
diff changeset
23 %this' and 'bool %that' all over the place, I think it would be
anatofuz
parents:
diff changeset
24 disorienting to see:
anatofuz
parents:
diff changeset
25
anatofuz
parents:
diff changeset
26 br %predicate, %iftrue, %iffalse
anatofuz
parents:
diff changeset
27
anatofuz
parents:
diff changeset
28 for branches. Even just typing that once gives me the creeps. ;) Like I
anatofuz
parents:
diff changeset
29 said, we should probably discuss this further in person...
anatofuz
parents:
diff changeset
30
anatofuz
parents:
diff changeset
31 > On reflection, I really like your idea of having the two different
anatofuz
parents:
diff changeset
32 > switch types (even though they encode implementation techniques rather
anatofuz
parents:
diff changeset
33 > than semantics). It should simplify building the CFG and my guess is it
anatofuz
parents:
diff changeset
34 > could enable some significant optimizations, though we should think
anatofuz
parents:
diff changeset
35 > about which.
anatofuz
parents:
diff changeset
36
anatofuz
parents:
diff changeset
37 Great. I added a note to the switch section commenting on how the VM
anatofuz
parents:
diff changeset
38 should just use the instruction type as a hint, and that the
anatofuz
parents:
diff changeset
39 implementation may choose altermate representations (such as predicated
anatofuz
parents:
diff changeset
40 branches).
anatofuz
parents:
diff changeset
41
anatofuz
parents:
diff changeset
42 > In the lookup-indirect form of the switch, is there a reason not to
anatofuz
parents:
diff changeset
43 > make the val-type uint?
anatofuz
parents:
diff changeset
44
anatofuz
parents:
diff changeset
45 No. This was something I was debating for a while, and didn't really feel
anatofuz
parents:
diff changeset
46 strongly about either way. It is common to switch on other types in HLL's
anatofuz
parents:
diff changeset
47 (for example signed int's are particularly common), but in this case, all
anatofuz
parents:
diff changeset
48 that will be added is an additional 'cast' instruction. I removed that
anatofuz
parents:
diff changeset
49 from the spec.
anatofuz
parents:
diff changeset
50
anatofuz
parents:
diff changeset
51 > I agree with your comment that we don't need 'neg'
anatofuz
parents:
diff changeset
52
anatofuz
parents:
diff changeset
53 Removed.
anatofuz
parents:
diff changeset
54
anatofuz
parents:
diff changeset
55 > There's a trade-off with the cast instruction:
anatofuz
parents:
diff changeset
56 > + it avoids having to define all the upcasts and downcasts that are
anatofuz
parents:
diff changeset
57 > valid for the operands of each instruction (you probably have
anatofuz
parents:
diff changeset
58 > thought of other benefits also)
anatofuz
parents:
diff changeset
59 > - it could make the bytecode significantly larger because there could
anatofuz
parents:
diff changeset
60 > be a lot of cast operations
anatofuz
parents:
diff changeset
61
anatofuz
parents:
diff changeset
62 + You NEED casts to represent things like:
anatofuz
parents:
diff changeset
63 void foo(float);
anatofuz
parents:
diff changeset
64 ...
anatofuz
parents:
diff changeset
65 int x;
anatofuz
parents:
diff changeset
66 ...
anatofuz
parents:
diff changeset
67 foo(x);
anatofuz
parents:
diff changeset
68 in a language like C. Even in a Java like language, you need upcasts
anatofuz
parents:
diff changeset
69 and some way to implement dynamic downcasts.
anatofuz
parents:
diff changeset
70 + Not all forms of instructions take every type (for example you can't
anatofuz
parents:
diff changeset
71 shift by a floating point number of bits), thus SOME programs will need
anatofuz
parents:
diff changeset
72 implicit casts.
anatofuz
parents:
diff changeset
73
anatofuz
parents:
diff changeset
74 To be efficient and to avoid your '-' point above, we just have to be
anatofuz
parents:
diff changeset
75 careful to specify that the instructions shall operate on all common
anatofuz
parents:
diff changeset
76 types, therefore casting should be relatively uncommon. For example all
anatofuz
parents:
diff changeset
77 of the arithmetic operations work on almost all data types.
anatofuz
parents:
diff changeset
78
anatofuz
parents:
diff changeset
79 > Making the second arg. to 'shl' a ubyte seems good enough to me.
anatofuz
parents:
diff changeset
80 > 255 positions seems adequate for several generations of machines
anatofuz
parents:
diff changeset
81
anatofuz
parents:
diff changeset
82 Okay, that comment is removed.
anatofuz
parents:
diff changeset
83
anatofuz
parents:
diff changeset
84 > and is more compact than uint.
anatofuz
parents:
diff changeset
85
anatofuz
parents:
diff changeset
86 No, it isn't. Remember that the bytecode encoding saves value slots into
anatofuz
parents:
diff changeset
87 the bytecode instructions themselves, not constant values. This is
anatofuz
parents:
diff changeset
88 another case where we may introduce more cast instructions (but we will
anatofuz
parents:
diff changeset
89 also reduce the number of opcode variants that must be supported by a
anatofuz
parents:
diff changeset
90 virtual machine). Because most shifts are by constant values, I don't
anatofuz
parents:
diff changeset
91 think that we'll have to cast many shifts. :)
anatofuz
parents:
diff changeset
92
anatofuz
parents:
diff changeset
93 > I still have some major concerns about including malloc and free in the
anatofuz
parents:
diff changeset
94 > language (either as builtin functions or instructions).
anatofuz
parents:
diff changeset
95
anatofuz
parents:
diff changeset
96 Agreed. How about this proposal:
anatofuz
parents:
diff changeset
97
anatofuz
parents:
diff changeset
98 malloc/free are either built in functions or actual opcodes. They provide
anatofuz
parents:
diff changeset
99 all of the type safety that the document would indicate, blah blah
anatofuz
parents:
diff changeset
100 blah. :)
anatofuz
parents:
diff changeset
101
anatofuz
parents:
diff changeset
102 Now, because of all of the excellent points that you raised, an
anatofuz
parents:
diff changeset
103 implementation may want to override the default malloc/free behavior of
anatofuz
parents:
diff changeset
104 the program. To do this, they simply implement a "malloc" and
anatofuz
parents:
diff changeset
105 "free" function. The virtual machine will then be defined to use the user
anatofuz
parents:
diff changeset
106 defined malloc/free function (which return/take void*'s, not type'd
anatofuz
parents:
diff changeset
107 pointers like the builtin function would) if one is available, otherwise
anatofuz
parents:
diff changeset
108 fall back on a system malloc/free.
anatofuz
parents:
diff changeset
109
anatofuz
parents:
diff changeset
110 Does this sound like a good compromise? It would give us all of the
anatofuz
parents:
diff changeset
111 typesafety/elegance in the language while still allowing the user to do
anatofuz
parents:
diff changeset
112 all the cool stuff they want to...
anatofuz
parents:
diff changeset
113
anatofuz
parents:
diff changeset
114 > 'alloca' on the other hand sounds like a good idea, and the
anatofuz
parents:
diff changeset
115 > implementation seems fairly language-independent so it doesn't have the
anatofuz
parents:
diff changeset
116 > problems with malloc listed above.
anatofuz
parents:
diff changeset
117
anatofuz
parents:
diff changeset
118 Okay, once we get the above stuff figured out, I'll put it all in the
anatofuz
parents:
diff changeset
119 spec.
anatofuz
parents:
diff changeset
120
anatofuz
parents:
diff changeset
121 > About indirect call:
anatofuz
parents:
diff changeset
122 > Your option #2 sounded good to me. I'm not sure I understand your
anatofuz
parents:
diff changeset
123 > concern about an explicit 'icall' instruction?
anatofuz
parents:
diff changeset
124
anatofuz
parents:
diff changeset
125 I worry too much. :) The other alternative has been removed. 'icall' is
anatofuz
parents:
diff changeset
126 now up in the instruction list next to 'call'.
anatofuz
parents:
diff changeset
127
anatofuz
parents:
diff changeset
128 > I believe tail calls are relatively easy to identify; do you know why
anatofuz
parents:
diff changeset
129 > .NET has a tailcall instruction?
anatofuz
parents:
diff changeset
130
anatofuz
parents:
diff changeset
131 Although I am just guessing, I believe it probably has to do with the fact
anatofuz
parents:
diff changeset
132 that they want languages like Haskell and lisp to be efficiently runnable
anatofuz
parents:
diff changeset
133 on their VM. Of course this means that the VM MUST implement tail calls
anatofuz
parents:
diff changeset
134 'correctly', or else life will suck. :) I would put this into a future
anatofuz
parents:
diff changeset
135 feature bin, because it could be pretty handy...
anatofuz
parents:
diff changeset
136
anatofuz
parents:
diff changeset
137 > A pair of important synchronization instr'ns to think about:
anatofuz
parents:
diff changeset
138 > load-linked
anatofuz
parents:
diff changeset
139 > store-conditional
anatofuz
parents:
diff changeset
140
anatofuz
parents:
diff changeset
141 What is 'load-linked'? I think that (at least for now) I should add these
anatofuz
parents:
diff changeset
142 to the 'possible extensions' section, because they are not immediately
anatofuz
parents:
diff changeset
143 needed...
anatofuz
parents:
diff changeset
144
anatofuz
parents:
diff changeset
145 > Other classes of instructions that are valuable for pipeline
anatofuz
parents:
diff changeset
146 > performance:
anatofuz
parents:
diff changeset
147 > conditional-move
anatofuz
parents:
diff changeset
148 > predicated instructions
anatofuz
parents:
diff changeset
149
anatofuz
parents:
diff changeset
150 Conditional move is effectly a special case of a predicated
anatofuz
parents:
diff changeset
151 instruction... and I think that all predicated instructions can possibly
anatofuz
parents:
diff changeset
152 be implemented later in LLVM. It would significantly change things, and
anatofuz
parents:
diff changeset
153 it doesn't seem to be very necessary right now. It would seem to
anatofuz
parents:
diff changeset
154 complicate flow control analysis a LOT in the virtual machine. I would
anatofuz
parents:
diff changeset
155 tend to prefer that a predicated architecture like IA64 convert from a
anatofuz
parents:
diff changeset
156 "basic block" representation to a predicated rep as part of it's dynamic
anatofuz
parents:
diff changeset
157 complication phase. Also, if a basic block contains ONLY a move, then
anatofuz
parents:
diff changeset
158 that can be trivally translated into a conditional move...
anatofuz
parents:
diff changeset
159
anatofuz
parents:
diff changeset
160 > I agree that we need a static data space. Otherwise, emulating global
anatofuz
parents:
diff changeset
161 > data gets unnecessarily complex.
anatofuz
parents:
diff changeset
162
anatofuz
parents:
diff changeset
163 Definitely. Also a later item though. :)
anatofuz
parents:
diff changeset
164
anatofuz
parents:
diff changeset
165 > We once talked about adding a symbolic thread-id field to each
anatofuz
parents:
diff changeset
166 > ..
anatofuz
parents:
diff changeset
167 > Instead, it could a great topic for a separate study.
anatofuz
parents:
diff changeset
168
anatofuz
parents:
diff changeset
169 Agreed. :)
anatofuz
parents:
diff changeset
170
anatofuz
parents:
diff changeset
171 > What is the semantics of the IA64 stop bit?
anatofuz
parents:
diff changeset
172
anatofuz
parents:
diff changeset
173 Basically, the IA64 writes instructions like this:
anatofuz
parents:
diff changeset
174 mov ...
anatofuz
parents:
diff changeset
175 add ...
anatofuz
parents:
diff changeset
176 sub ...
anatofuz
parents:
diff changeset
177 op xxx
anatofuz
parents:
diff changeset
178 op xxx
anatofuz
parents:
diff changeset
179 ;;
anatofuz
parents:
diff changeset
180 mov ...
anatofuz
parents:
diff changeset
181 add ...
anatofuz
parents:
diff changeset
182 sub ...
anatofuz
parents:
diff changeset
183 op xxx
anatofuz
parents:
diff changeset
184 op xxx
anatofuz
parents:
diff changeset
185 ;;
anatofuz
parents:
diff changeset
186
anatofuz
parents:
diff changeset
187 Where the ;; delimits a group of instruction with no dependencies between
anatofuz
parents:
diff changeset
188 them, which can all be executed concurrently (to the limits of the
anatofuz
parents:
diff changeset
189 available functional units). The ;; gets translated into a bit set in one
anatofuz
parents:
diff changeset
190 of the opcodes.
anatofuz
parents:
diff changeset
191
anatofuz
parents:
diff changeset
192 The advantages of this representation is that you don't have to do some
anatofuz
parents:
diff changeset
193 kind of 'thread id scheduling' pass by having to specify ahead of time how
anatofuz
parents:
diff changeset
194 many threads to use, and the representation doesn't have a per instruction
anatofuz
parents:
diff changeset
195 overhead...
anatofuz
parents:
diff changeset
196
anatofuz
parents:
diff changeset
197 > And finally, another thought about the syntax for arrays :-)
anatofuz
parents:
diff changeset
198 > Although this syntax:
anatofuz
parents:
diff changeset
199 > array <dimension-list> of <type>
anatofuz
parents:
diff changeset
200 > is verbose, it will be used only in the human-readable assembly code so
anatofuz
parents:
diff changeset
201 > size should not matter. I think we should consider it because I find it
anatofuz
parents:
diff changeset
202 > to be the clearest syntax. It could even make arrays of function
anatofuz
parents:
diff changeset
203 > pointers somewhat readable.
anatofuz
parents:
diff changeset
204
anatofuz
parents:
diff changeset
205 My only comment will be to give you an example of why this is a bad
anatofuz
parents:
diff changeset
206 idea. :)
anatofuz
parents:
diff changeset
207
anatofuz
parents:
diff changeset
208 Here is an example of using the switch statement (with my recommended
anatofuz
parents:
diff changeset
209 syntax):
anatofuz
parents:
diff changeset
210
anatofuz
parents:
diff changeset
211 switch uint %val, label %otherwise,
anatofuz
parents:
diff changeset
212 [%3 x {uint, label}] [ { uint %57, label %l1 },
anatofuz
parents:
diff changeset
213 { uint %20, label %l2 },
anatofuz
parents:
diff changeset
214 { uint %14, label %l3 } ]
anatofuz
parents:
diff changeset
215
anatofuz
parents:
diff changeset
216 Here it is with the syntax you are proposing:
anatofuz
parents:
diff changeset
217
anatofuz
parents:
diff changeset
218 switch uint %val, label %otherwise,
anatofuz
parents:
diff changeset
219 array %3 of {uint, label}
anatofuz
parents:
diff changeset
220 array of {uint, label}
anatofuz
parents:
diff changeset
221 { uint %57, label %l1 },
anatofuz
parents:
diff changeset
222 { uint %20, label %l2 },
anatofuz
parents:
diff changeset
223 { uint %14, label %l3 }
anatofuz
parents:
diff changeset
224
anatofuz
parents:
diff changeset
225 Which is ambiguous and very verbose. It would be possible to specify
anatofuz
parents:
diff changeset
226 constants with [] brackets as in my syntax, which would look like this:
anatofuz
parents:
diff changeset
227
anatofuz
parents:
diff changeset
228 switch uint %val, label %otherwise,
anatofuz
parents:
diff changeset
229 array %3 of {uint, label} [ { uint %57, label %l1 },
anatofuz
parents:
diff changeset
230 { uint %20, label %l2 },
anatofuz
parents:
diff changeset
231 { uint %14, label %l3 } ]
anatofuz
parents:
diff changeset
232
anatofuz
parents:
diff changeset
233 But then the syntax is inconsistent between type definition and constant
anatofuz
parents:
diff changeset
234 definition (why do []'s enclose the constants but not the types??).
anatofuz
parents:
diff changeset
235
anatofuz
parents:
diff changeset
236 Anyways, I'm sure that there is much debate still to be had over
anatofuz
parents:
diff changeset
237 this... :)
anatofuz
parents:
diff changeset
238
anatofuz
parents:
diff changeset
239 -Chris
anatofuz
parents:
diff changeset
240
anatofuz
parents:
diff changeset
241 http://www.nondot.org/~sabre/os/
anatofuz
parents:
diff changeset
242 http://www.nondot.org/MagicStats/
anatofuz
parents:
diff changeset
243 http://korbit.sourceforge.net/
anatofuz
parents:
diff changeset
244
anatofuz
parents:
diff changeset
245