@@ -248,13 +248,14 @@ which is a term made up for HLSL. A cx-value is a temporary value which may be
248248the result of a cast, and stores its value back to an lvalue when the value
249249expires.
250250
251- To represent this concept in Clang we introduce a new ``HLSLOutParamExpr ``. An
252- ``HLSLOutParamExpr `` has two forms, one with a single sub-expression and one
253- with two sub-expressions.
251+ To represent this concept in Clang we introduce a new ``HLSLOutArgExpr ``. An
252+ ``HLSLOutArgExpr `` has three sub-expressions:
254253
255- The single sub-expression form is used when the argument expression and the
256- function parameter are the same type, so no cast is required. As in this
257- example:
254+ * An OpaqueValueExpr of the argument lvalue expression.
255+ * An OpaqueValueExpr of the copy-initialized parameter temporary.
256+ * A BinaryOpExpr assigning the first with the value of the second.
257+
258+ Given this example:
258259
259260.. code-block :: c++
260261
@@ -267,23 +268,36 @@ example:
267268 Init(V);
268269 }
269270
270- The expected AST formulation for this code would be something like:
271+ The expected AST formulation for this code would be something like the example
272+ below. Due to the nature of OpaqueValueExpr nodes, the nodes repeat in the AST
273+ dump. The fake addresses ``0xSOURCE `` and ``0xTEMPORARY `` denote the source
274+ lvalue and argument temporary lvalue expressions.
271275
272276.. code-block :: text
273277
274278 CallExpr 'void'
275279 |-ImplicitCastExpr 'void (*)(int &)' <FunctionToPointerDecay>
276280 | `-DeclRefExpr 'void (int &)' lvalue Function 'Init' 'void (int &)'
277- |-HLSLOutParamExpr 'int' lvalue inout
278- `-DeclRefExpr 'int' lvalue Var 'V' 'int'
279-
280- The ``HLSLOutParamExpr `` captures that the value is ``inout `` vs ``out `` to
281- denote whether or not the temporary is initialized from the sub-expression. If
282- no casting is required the sub-expression denotes the lvalue expression that the
283- cx-value will be copied to when the value expires.
284-
285- The two sub-expression form of the AST node is required when the argument type
286- is not the same as the parameter type. Given this example:
281+ `-HLSLOutArgExpr <col:10> 'int' lvalue inout
282+ |-OpaqueValueExpr 0xSOURCE <col:10> 'int' lvalue
283+ | `-DeclRefExpr <col:10> 'int' lvalue Var 'V' 'int'
284+ |-OpaqueValueExpr 0xTEMPORARY <col:10> 'int' lvalue
285+ | `-ImplicitCastExpr <col:10> 'int' <LValueToRValue>
286+ | `-OpaqueValueExpr 0xSOURCE <col:10> 'int' lvalue
287+ | `-DeclRefExpr <col:10> 'int' lvalue Var 'V' 'int'
288+ `-BinaryOperator <col:10> 'int' lvalue '='
289+ |-OpaqueValueExpr 0xSOURCE <col:10> 'int' lvalue
290+ | `-DeclRefExpr <col:10> 'int' lvalue Var 'V' 'int'
291+ `-ImplicitCastExpr <col:10> 'int' <LValueToRValue>
292+ `-OpaqueValueExpr 0xTEMPORARY <col:10> 'int' lvalue
293+ `-ImplicitCastExpr <col:10> 'int' <LValueToRValue>
294+ `-OpaqueValueExpr 0xSOURCE <col:10> 'int' lvalue
295+ `-DeclRefExpr <col:10> 'int' lvalue Var 'V' 'int'
296+
297+ The ``HLSLOutArgExpr `` captures that the value is ``inout `` vs ``out `` to
298+ denote whether or not the temporary is initialized from the sub-expression.
299+
300+ The example below demonstrates argument casting:
287301
288302.. code-block :: c++
289303
@@ -295,28 +309,39 @@ is not the same as the parameter type. Given this example:
295309 Trunc(F);
296310 }
297311
298- For this case the ``HLSLOutParamExpr `` will have sub-expressions to record both
312+ For this case the ``HLSLOutArgExpr `` will have sub-expressions to record both
299313casting expression sequences for the initialization and write back:
300314
301315.. code-block :: text
302316
303317 -CallExpr 'void'
304318 |-ImplicitCastExpr 'void (*)(int3 &)' <FunctionToPointerDecay>
305319 | `-DeclRefExpr 'void (int3 &)' lvalue Function 'inc_i32' 'void (int3 &)'
306- `-HLSLOutParamExpr 'int3' lvalue inout
307- |-ImplicitCastExpr 'float3' <IntegralToFloating>
308- | `-ImplicitCastExpr 'int3' <LValueToRValue>
309- | `-OpaqueValueExpr 'int3' lvalue
310- `-ImplicitCastExpr 'int3' <FloatingToIntegral>
311- `-ImplicitCastExpr 'float3' <LValueToRValue>
312- `-DeclRefExpr 'float3' lvalue 'F' 'float3'
313-
314- In this formation the write-back casts are captured as the first sub-expression
315- and they cast from an ``OpaqueValueExpr ``. In IR generation we can use the
316- ``OpaqueValueExpr `` as a placeholder for the ``HLSLOutParamExpr ``'s temporary
317- value on function return.
318-
319- In code generation this can be implemented with some targeted extensions to the
320- Objective-C write-back support. Specifically extending CGCall.cpp's
321- ``EmitWriteback `` function to support casting expressions and emission of
322- aggregate lvalues.
320+ `-HLSLOutArgExpr <col:11> 'int3':'vector<int, 3>' lvalue inout
321+ |-OpaqueValueExpr 0xSOURCE <col:11> 'float3':'vector<float, 3>' lvalue
322+ | `-DeclRefExpr <col:11> 'float3':'vector<float, 3>' lvalue Var 'F' 'float3':'vector<float, 3>'
323+ |-OpaqueValueExpr 0xTEMPORARY <col:11> 'int3':'vector<int, 3>' lvalue
324+ | `-ImplicitCastExpr <col:11> 'vector<int, 3>' <FloatingToIntegral>
325+ | `-ImplicitCastExpr <col:11> 'float3':'vector<float, 3>' <LValueToRValue>
326+ | `-OpaqueValueExpr 0xSOURCE <col:11> 'float3':'vector<float, 3>' lvalue
327+ | `-DeclRefExpr <col:11> 'float3':'vector<float, 3>' lvalue Var 'F' 'float3':'vector<float, 3>'
328+ `-BinaryOperator <col:11> 'float3':'vector<float, 3>' lvalue '='
329+ |-OpaqueValueExpr 0xSOURCE <col:11> 'float3':'vector<float, 3>' lvalue
330+ | `-DeclRefExpr <col:11> 'float3':'vector<float, 3>' lvalue Var 'F' 'float3':'vector<float, 3>'
331+ `-ImplicitCastExpr <col:11> 'vector<float, 3>' <IntegralToFloating>
332+ `-ImplicitCastExpr <col:11> 'int3':'vector<int, 3>' <LValueToRValue>
333+ `-OpaqueValueExpr 0xTEMPORARY <col:11> 'int3':'vector<int, 3>' lvalue
334+ `-ImplicitCastExpr <col:11> 'vector<int, 3>' <FloatingToIntegral>
335+ `-ImplicitCastExpr <col:11> 'float3':'vector<float, 3>' <LValueToRValue>
336+ `-OpaqueValueExpr 0xSOURCE <col:11> 'float3':'vector<float, 3>' lvalue
337+ `-DeclRefExpr <col:11> 'float3':'vector<float, 3>' lvalue Var 'F' 'float3':'vector<float, 3>'
338+
339+ The AST representation is the same whether casting is required or not, which
340+ simplifies the code generation. IR generation does the following:
341+
342+ * Emit the argument lvalue expression.
343+ * Initialize the argument:
344+ * For ``inout `` arguments, emit the copy-initialization expression.
345+ * For ``out `` arguments, emit an uninitialized temporary.
346+ * Emit the call
347+ * Emit the write-back BinaryOperator expression.
0 commit comments