주의 : 답이 틀릴 수도 있습니다. 그냥 정리하는 용도로 올립니다. 혹시라도 도움이 필요한 분이 있다면 도움이 되었으면 좋겠네요.

주의 : 특별한 경우가 아니라면, 귀찮아서 문제는 안 옮깁니다.

경고 : 숙제하려고 베끼는 데 사용하지 마십시오. 본인의 미래를 망칠 뿐입니다. 나중에 저를 원망하지 마세요.

부탁 : 문제 풀이가 잘못되었으면 지적해 주셨으면 좋겠습니다.



  • 탄환 최대 도달거리 : 1 km

  • 중력 가속도 : 10 m/s2

  • 대포 사정거리 : 100 km


총탄 초기속도와 포탄 초기 속도를 구하는 문제입니다. 최대 도달거리라는 조건이 주어졌으므로, 45 도 각도로 포물선 운동하는 물체여야 합니다.


처음에는 H 에서 수평으로 던져졌다고 생각하고 문제를 풀었는데, 아주 괴랄한 식이 나오더군요. 그런데 물잘알 친구 햄이 "최대" 라는 전제조건을 깔았기 때문에 45 도로 던져져야 한다고 지적해 줘서 다시 문제를 풀었습니다.


사실 왜 45 도에서 최대 거리가 나오는지 증명부터 해야 하지만 귀찮으니 그냥 넘어 가도록 하겠습니다. 나중에 시간나면 추가하겠습니다.


각도 Θ 로 던져진 공이 있다고 했을 때 그것의 초기속도 v0 는 중력방향에 대한 수직성분 및 수평성분 속도로 나뉩니다.


식 1.


그리고 시간 t 가 지났을 때 속도는 다음과 같습니다.


식 2.


만약 시간 t 에서 수직성분 속도가 0 이 된다면, t 일 때 최대 높이가 됩니다.


식 3.


포물선 운동은 최대 높이에서 중력축에 대해서 좌우대칭인 모양을 보여 주기 때문에 땅에 떨어졌을 때의 시간은 2t 가 됩니다. 그러므로 시간 2t 까지의 이동거리를 구하면 됩니다.


수평성분 이동거리는 다음과 같습니다.


식 4.

식 4 에 의해 총탄의 초기속도는 다음과 같습니다.


식 5.



식 4 에 의해 포탄의 초기속도는 다음과 같습니다.


식 6.

주의 : 답이 틀릴 수도 있습니다. 그냥 정리하는 용도로 올립니다. 혹시라도 도움이 필요한 분이 있다면 도움이 되었으면 좋겠네요.

경고 : 숙제하려고 베끼는 데 사용하지 마십시오. 본인의 미래를 망칠 뿐입니다. 나중에 저를 원망하지 마세요.

부탁 : 문제 풀이가 잘못되었으면 지적해 주셨으면 좋겠습니다.



다음은 포물선 운동에 관한 문제다. 각각 물음에 답하라.



( a ) 공중으로 던져진 공은 y = ax2 + bx + c 의 형태의 포물선 모양을 그리며 운동하는 것을 보여라.


( b ) 경사면 각도가 30 도인 언덕방향으로 v0 의 빠르기로 수평과 θ 의 각도로 던진 공이 있다. 공을 던진 점으로부터 수평거리를 x 라 할 때 이 경우 언덕 경사면 높이는 y = (1/2)x 로 나타낼 수 있다. 공이 도달한 언덕 높이는 얼마인가?



( a )


어떤 각도로 공중으로 던져진 공은 중력가속도 g 를 받습니다. 그래서 항상 속도와 위치가 변화합니다.


시간 t 에서 y 성분 속도 함수는 다음과 같습니다. 초기 속도가 중력가속도에 의해서 상쇠되면서 올라갔다가 떨어지는거죠.


식 1.


식 1 을 부정적분해서 위치함수( y 값 )를 구할 수 있습니다.


식 2.


이제 x 의 관점에서도 식 1 과 식 2 처럼 풀어 보도록 하겠습니다. 차이가 있다면 x 축 성분은 시간의 변화에도 영향을 받지 않는 상수라는 것입니다.


식 3.


이제 이를 x 와 y 의 관계로 나타내야 합니다.


식 3 에서 t 값을 구할 수 있습니다.


식 4.


t 값을 식 2 에 대입합니다.


식 5.


그러므로 던져진 공은 계수가 다음과 같은 포물선 운동을 한다고 할 수 있습니다.


식 6.


삼각함수를 사용하면 초기 속도의 수평성분과 수직성분을 구할 수 있습니다.


식 7.


우리는 최종적으로 식을 다음과 같이 정리할 수 있습니다.


식 8.

( b )


경사면과 공이 만났다는 이야기는 포물선과 경사면을 표현하는 그래프의 y 값이 동일하다는 의미입니다( 두 그래프가 만남 ). 그러므로 다음과 같은 식을 세울 수 있습니다.


식 7.


이 x 값 중에 첫 번째 해는 시작위치를 의미하므로 두 번째 해를 사용하면 됩니다. 두 번째 해를 y = (1/2)x 에다가 대입하도록 하겠습니다.


식 8.


해답은 다음과 같습니다.


식 11.


아무래도 해답이 오답인 것 같습니다.

주의 : 답이 틀릴 수도 있습니다. 그냥 정리하는 용도로 올립니다. 혹시라도 도움이 필요한 분이 있다면 도움이 되었으면 좋겠네요.

주의 : 특별한 경우가 아니라면, 귀찮아서 문제는 안 옮깁니다.

경고 : 숙제하려고 베끼는 데 사용하지 마십시오. 본인의 미래를 망칠 뿐입니다. 나중에 저를 원망하지 마세요.

부탁 : 문제 풀이가 잘못되었으면 지적해 주셨으면 좋겠습니다.



지표면으로부터 높이 H 인 곳에서, 공을 v0 의 빠르기로 수평과 θ 의 각도로 위로 향해 던졌다. 공이 지표면에 닿기까지 공이 수평방향으로 이동한 거리는 얼마인가?


  • 중력 가속도 : g

  • 최고점에 도달하는 시간 : th

  • 최고점에서 땅에 떨어지는 시간 : tl


그림 1.


일단 이 문제를 해결하기 위해서는 공이 땅에 떨어지는 시간을 구해야 합니다.


던진 공의 초기 속도 분해


공은 θ 의 각도로 던져지고 있으므로 이것을 수평성분( x )과 수직성분( y )으로 나누면 다음과 같습니다.


식 1.


공의 수직 성분 속도


공에는 지속적으로 중력 가속도가 가해지므로 시간 t 에서의 속도는 다음과 같습니다.


식 2.


최고점에 도달하는 시간


그런데 최고점에 도달하는 경우는 속도의 크기가 0 이 되는 경우입니다. 그러므로 최고점에 도달하는 시간 th 는 다음과 같이 구할 수 있습니다.


식 3.

최고점까지의 이동 거리



먼저 식 2 의 속도함수를 부정적분해 이동거리함수의 원함수를 구합니다.


식 4.


 [ 0, th ] 의 범위로 정적분하면 최고점까지의 이동거리가 됩니다.


식 5.


최고점의 높이


그런데 이것은 시간 th 까지의 이동거리이므로 최고점에서의 높이는 공을 던진 초기 높이인 H 에서 이동거리를 더한 값이 되어야 합니다. 여기에서 P 는 위치 함수입니다.


식 6.


자유낙하 운동 속도


이제 최고점의 높이를 구했으니, 시간 th 부터는 자유낙하 운동을 하게 됩니다.


자유낙하 운동을 하고 있을 때 속도 함수는 다음과 같습니다.


식 7.


자유낙하 운동 이동 거리


자유낙하 속도 함수를 부정적분해서 이동거리 함수의 원함수를 구합니다.


식 8.


자유낙하 시간


자유낙하 이동 거리는 최고점의 높이와 같아야 합니다. 그러므로 다음이 성립해야 합니다.


식 9.


그런데 t 는 자유낙하 시간만을 의미하기 때문에 실제 tl 은 다음과 같습니다.


식 10.


수평 성분 이동거리


문제에서는 공기저항에 대해서 언급하지 않고 있기 때문에, 관성에 의해서 수평이동 운동은 등속도 운동이 됩니다. 그러므로 다음이 성립합니다.


식 11.


식 11 에 공이 바닥에 도달하기까지의 시간  tl  을 대입하면 다음과 같습니다.


식 12.


우리는 식 1 에서 초기속도를 계산했으므로, 이를 식 12 에 대입해서 최종 결과를 구할 수 있습니다.


식 13.


그런데 해답에서는 루트 안의 뒤쪽 항이 4gH 군요. 몇 번 검증해 봤는데, 해답이 오답인 것 같습니다.

주의 : 초심자 튜토리얼은 아닙니다. 그러므로, 실제 API 호출 용례를 알고자 한다면, 샘플이나 튜토리얼을 찾아서 확인해 보세요.

주의 : 완전히 이해하고 작성한 글이 아니므로 잘못된 내용이 포함되어 있을 수 있습니다.

주의 : 이상하면 참고자료를 확인하세요.



HLSL to SPIR-V Feature Mapping Manual ] 에 커맨드라인 옵션들에 대한 설명들이 나와 있기는 하지만, 정확하게 어떤 것을 이야기하는지 이해할 수 없는 것들도 있습니다.


그래서 소스 코드를 분석해서 정확하게 각 옵션들의 의미를 파악해 보기로 했습니다. 아래 블록은 "dxc -help" 를 실행했을 때 나오는 설명들입니다. SPIR-V 전용 옵션들은 여기에서는 배제했습니다. 나중에 다른 챕터에서 다룰 계획입니다.


Common Options:

  -help              Display available options

  -nologo            Suppress copyright message

  -Qunused-arguments Don't emit warning for unused driver arguments


Compilation Options:

  -all_resources_bound    Enables agressive flattening

  -auto-binding-space <value>

                          Set auto binding space - enables auto resource binding in libraries

  -Cc                     Output color coded assembly listings

  -default-linkage <value>

                          Set default linkage for non-shader functions when compiling or linking to a library target (internal, external)

  -denorm <value>         select denormal value options (any, preserve, ftz). any is the default.

  -D <value>              Define macro

  -enable-16bit-types     Enable 16bit types and disable min precision types. Available in HLSL 2018 and shader model 6.2

  -export-shaders-only    Only export shaders when compiling a library

  -exports <value>        Specify exports when compiling a library: export1[[,export1_clone,...]=internal_name][;...]

  -E <value>              Entry point name

  -Fc <file>              Output assembly code listing file

  -Fd <file>              Write debug information to the given file, or automatically named file in directory when ending in '\'

  -Fe <file>              Output warnings and errors to the given file

  -Fh <file>              Output header file containing object code

  -flegacy-macro-expansion

                          Expand the operands before performing token-pasting operation (fxc behavior)

  -flegacy-resource-reservation

                          Reserve unused explicit register assignments for compatibility with shader model 5.0 and below

  -force_rootsig_ver <profile>

                          force root signature version (rootsig_1_1 if omitted)

  -Fo <file>              Output object file

  -Gec                    Enable backward compatibility mode

  -Ges                    Enable strict mode

  -Gfa                    Avoid flow control constructs

  -Gfp                    Prefer flow control constructs

  -Gis                    Force IEEE strictness

  -HV <value>             HLSL version (2016, 2017, 2018). Default is 2018

  -H                      Show header includes and nesting depth

  -ignore-line-directives Ignore line directives

  -I <value>              Add directory to include search path

  -Lx                     Output hexadecimal literals

  -Ni                     Output instruction numbers in assembly listings

  -no-warnings            Suppress warnings

  -not_use_legacy_cbuf_load

                          Do not use legacy cbuffer load

  -No                     Output instruction byte offsets in assembly listings

  -Odump                  Print the optimizer commands.

  -Od                     Disable optimizations

  -pack_optimized         Optimize signature packing assuming identical signature provided for each connecting stage

  -pack_prefix_stable     (default) Pack signatures preserving prefix-stable property - appended elements will not disturb placement of prior elements

  -recompile              recompile from DXIL container with Debug Info or Debug Info bitcode file

  -res_may_alias          Assume that UAVs/SRVs may alias

  -rootsig-define <value> Read root signature from a #define

  -T <profile>            Set target profile.

        <profile>: ps_6_0, ps_6_1, ps_6_2, ps_6_3, ps_6_4, ps_6_5,

                 vs_6_0, vs_6_1, vs_6_2, vs_6_3, vs_6_4, vs_6_5,

                 cs_6_0, cs_6_1, cs_6_2, cs_6_3, cs_6_4, cs_6_5,

                 gs_6_0, gs_6_1, gs_6_2, gs_6_3, gs_6_4, gs_6_5,

                 ds_6_0, ds_6_1, ds_6_2, ds_6_3, ds_6_4, ds_6_5,

                 hs_6_0, hs_6_1, hs_6_2, hs_6_3, hs_6_4, hs_6_5,

                 lib_6_3, lib_6_4, lib_6_5, ms_6_5, as_6_5

  -Vd                     Disable validation

  -Vi                     Display details about the include process.

  -Vn <name>              Use <name> as variable name in header file

  -WX                     Treat warnings as errors

  -Zi                     Enable debug information

  -Zpc                    Pack matrices in column-major order

  -Zpr                    Pack matrices in row-major order

  -Zsb                    Build debug name considering only output binary

  -Zss                    Build debug name considering source information


Optimization Options:

  -O0 Optimization Level 0

  -O1 Optimization Level 1

  -O2 Optimization Level 2

  -O3 Optimization Level 3 (Default)


SPIR-V CodeGen Options:

  -fspv-debug=<value>     Specify whitelist of debug info category (file -> source -> line, tool)

  -fspv-extension=<value> Specify SPIR-V extension permitted to use

  -fspv-reflect           Emit additional SPIR-V instructions to aid reflection

  -fspv-target-env=<value>

                          Specify the target environment: vulkan1.0 (default) or vulkan1.1

  -fvk-b-shift <shift> <space>

                          Specify Vulkan binding number shift for b-type register

  -fvk-bind-globals <binding> <set>

                          Specify Vulkan binding number and set number for the $Globals cbuffer

  -fvk-bind-register <type-number> <space> <binding> <set>

                          Specify Vulkan descriptor set and binding for a specific register

  -fvk-invert-y           Negate SV_Position.y before writing to stage output in VS/DS/GS to accommodate Vulkan's coordinate system

  -fvk-s-shift <shift> <space>

                          Specify Vulkan binding number shift for s-type register

  -fvk-t-shift <shift> <space>

                          Specify Vulkan binding number shift for t-type register

  -fvk-u-shift <shift> <space>

                          Specify Vulkan binding number shift for u-type register

  -fvk-use-dx-layout      Use DirectX memory layout for Vulkan resources

  -fvk-use-dx-position-w  Reciprocate SV_Position.w after reading from stage input in PS to accommodate the difference between Vulkan and DirectX

  -fvk-use-gl-layout      Use strict OpenGL std140/std430 memory layout for Vulkan resources

  -fvk-use-scalar-layout  Use scalar memory layout for Vulkan resources

  -Oconfig=<value>        Specify a comma-separated list of SPIRV-Tools passes to customize optimization configuration (see http://khr.io/hlsl2spirv#optimization)

  -spirv                  Generate SPIR-V code


Utility Options:

  -dumpbin              Load a binary file rather than compiling

  -extractrootsignature Extract root signature from shader bytecode (must be used with /Fo <file>)

  -getprivate <file>    Save private data from shader blob

  -P <value>            Preprocess to file (must be used alone)

  -Qembed_debug         Embed PDB in shader container (must be used with /Zi)

  -Qstrip_debug         Strip debug information from 4_0+ shader bytecode  (must be used with /Fo <file>)

  -Qstrip_priv          Strip private data from shader bytecode  (must be used with /Fo <file>)

  -Qstrip_reflect       Strip reflection data from shader bytecode  (must be used with /Fo <file>)

  -Qstrip_rootsignature Strip root signature data from shader bytecode  (must be used with /Fo <file>)

  -setprivate <file>    Private data to add to compiled shader blob

  -setrootsignature <file>

                        Attach root signature to shader bytecode

  -verifyrootsignature <file>

                        Verify shader bytecode with root signature


이 옵션들을 모두 살펴 볼 것은 아니구요, 그냥 -help 만 봐도 쉽게 이해할 수 있는 것들은 배제하겠습니다. 그리고 별로 빈도가 높아 보이지 않는 것들도 배제했습니다. 댓글로 특정 옵션에 대한 정확한 동작에 대해서 문의하신다면 내용을 추가하도록 하겠습니다.


기본 형식


다음과 같이 옵션 다음에 컴파일할 소스 파일 경로를 넣습니다.


dxc [ options... ] $(SourceFilePath)


$(SourceFilePath) 는 커맨드 실행 디렉토리에 대한 상대 경로일 수도 있고 절대 경로일 수도 있습니다.


옵션을 위한 플래그들은 '-' 접두어로 시작하며, 값을 받는 옵션이라면 "-O" 를 제외하고는 모두 한 칸을 띄고 값을 입력합니다.


-spriv


가장 먼저 지정해야 할 값이 없는 옵션입니다. SPIR-V 파일을 생성하라는 의미입니다. 벌칸을 사용한다는 가정하에서지만, 이것을 빼먹어서는 안 됩니다.


dxc -spirv


-T


셰이더 프로우파일 문자열입니다.


dxc -T $(shader_name)_$(major_version)_$(minor_version)


$(shader_name) 은 각 셰이더 타입의 머리글자 혹은 약자입니다.


  • vs : Vertex Shader.

  • hs : Hull Shader.

  • ds : Domain Shader.

  • gs : Geometry Shader.

  • ps : Pixel Shader.

  • cs : Compute Shader.

  • lib : shader LIBrary. 한 번도 써 본 적이 없어서 모르겠는데, [ Using shader linking ] 에서 정보를 얻을 수 있습니다.


문제는 셰이더의 버전인데요, 이것은 메이저와 마이너로 나뉩니다. 이것을 임의로 지정하는 것은 아니구요, [ Shader Models vs Shader Profiles ] 에 가면 셰이더 모델에서 이용가능한 셰이더 프로우파일들의 목록을 확인하실 수 있습니다.


-E


셰이더 프로우파일에 대한 진입 함수에 대한 문자열입니다. 


dxc -E mainVS


그냥 함수 이름을 기입하면 됩니다. 만약 이를 지정하지 않으면 기본적으로는 "main" 이 사용됩니다.


-D


디파인 매크로를 설정하는 문자열입니다.


만약 여러 개의 매크로를 설정해야 한다면, 여러 개의 -D 플래그를 사용해야 합니다. 예를 들면 아래 블록과 같이 할 수 있습니다.


dxc -D USE_POSITION -D USE_NORMAL=1


다들 아실거라 생각하지만 부연하자면, '=' 을 사용하지 않으면 "#ifdef" 를 사용해서 조건을 검사하고, 사용하면 "#if" 를 사용해서 조건을 검사합니다.


-I


HLSL 파일을 작성하다가 보면 인클루딩을 해야 하는 경우가 있습니다. 인클루딩해야 할 파일이 존재하는 폴더 경로에 대한 문자열입니다.



공용 HLSL 파일을 위한 폴더를 나누거나 종류별로 HLSL 파일을 나눠서 관리하다가 보면, 인클루드해야 하는 파일이 다른 디렉토리에 존재할 수 있습니다. 만약 같은 폴더에 대상 파일이 존재한다면 아무런 문제가 없지만, 그렇지 않다면 아래처럼 경로를 지정해야 합니다.


dxc -I C:\OtherFolder1 -I C:\OtherFolder2 -I ..\


여러 개의 폴더를 지정하려면 여러 개의 -I 플래그를 사용합니다. 경로는 절대 경로여도 되고 커맨드를 실행한 폴더에 대한 상대 경로여도 됩니다.


-O


최적화 수준을 지정하는 문자열입니다. 


이것은 특이하게 한칸 띄고 값을 지정하는 것이 아니라 바로 붙여서 지정합니다( 예를 들어 -O1 ).


dxc -O{0|1|2|3}


0 ~ 3 까지 지정할 수 있고 숫자가 낮을 수록 최적화를 덜 한다는 이야기입니다. 값의 크기는 코드를 생성하는 속도와 반비례하며 코드 실행 속도와 비례합니다.


-Fo


SPIR-V 를 생성할 경로에 대한 문자열입니다.


절대경로여도 되고 커맨드를 실행한 폴더에 대한 상대 경로여도 됩니다( 폴더를 지정하지 않으면 커맨드를 실행한 폴더에 생성됩니다 ).


이름은 마음대로 지정하시면 됩니다. 보통은 "[$(Identifier)_]$(StageName).spv" 라고 지정하는듯 합니다.


dxc -Fo my_vertex.spv


만약 이 옵션을 지정하지 않으면 콘솔창에다가 디스어셈블리 결과를 출력합니다.


-Fc


-Fo 에서 지정한 SPIR-V 파일에 대한 디스어셈블리 파일을 생성할 경로에 대한 문자열입니다. 


절대경로여도 되고 커맨드를 실행한 폴더에 대한 상대 경로여도 됩니다.


이름과 확장자는 마음대로 지정하시면 됩니다. 텍스트 파일로 생성되기 때문에 txt 인 것이 좋을 것 같습니다.


dxc -Fc my_vertex_disassembly.txt


-Fh


코드를 포함하고 있는 헤더 파일의 경로에 대한 문자열입니다.


dxc -Fh my_vertex_header.txt


헤더라고 하니, 엄청나게 헷갈리는데요, C/C++ 에서 사용할 수 있는 이진코드 배열을 정의하는 파일입니다. 열어 보니 디스어셈블리 내용도 포함하고 있더군요.


만약 코드에다가 SPIR-V 를 하드코딩하고 싶다면 이것을 사용할 수 있을 것 같네요.



-Fe


경고나 에러를 출력할 파일의 경로에 대한 문자열입니다. 만약 이 옵션을 지정하지 않으면 콘솔창에다가 결과를 출력합니다.


dxc -Fe my_vertex_output.txt


커맨드라인 프로그램을 사용하면 그 결과를 확인하기 위해서 stderr, stdout 에 대한 파이프를 만들어야 하는 경우가 있습니다. 매우 귀찮은 작업이죠.


그럴 경우에 텍스트로부터 한 번에 출력 결과를 읽어들일 수 있다면 매우 유용합니다.




주의할 점은 다음과 같습니다.


  • 성공시에는 아무런 로그도 남지 않습니다.

  • 표준 출력창의 내용을 redirect 한 것이므로 실패했을 경우에도 콘솔창에는 로그가 남지 않습니다.


주의 : 허락받고 번역한 것이 아니므로 언제든 내려갈 수 있습니다.

주의 : 번역이 개판이므로 이상하면 원문을 참조하세요.

원문 : Static single assignment form, Wikipedia.


컴퓨터 디자인에서, static single assignment form( 보통 SSA form 이나 단순하게 SSA 로 발음됨 ) 은 중간 표현( intermediate representation, IR )의 속성( property )입니다. 그것은 각 변수들이 정확히 한 번만 할당되고 모든 변수들은 그것이 사용되기 전에 정의될 것을 요구합니다. 원래의 IR 에서 현재 존재하는 변수들은 여러 버전들로 나뉩니다. 새로운 변수들은 일반적으로 텍스트북에서의 서브스크립트( subscript, 아래첨자 )를 원래 이름에 붙여서 식별됩니다. 그래서 모든 정의들은 자신만의 원래 버전을 획득하게 됩니다. SSA 폼에서 use-def chain 들은 명시적( explicit )이며, 각각은 단일 요소를 포함합니다.

SSA 는 Barry K.Rosen, Kark N. Wegman, F. Kenneth Zadeck 에 의해 1988 년에 제안되었습니다. IBM 에서 근무하던 Ron Crytron 과 Jeanne Ferrante 및 이전의 세 연구자들은 SSA 폼을 효율적으로 계산할 수 있는 알고리즘을 개발했습니다.

사람들은 Fortran 이나 C 를 위한 컴파일러에서 SSA 를 검색하는 것을 기대할 수 있습니다. 반면에 Scheme, ML, Haskell 과 같은 함수형 언어( functional language ) 컴파일러들에서는 continuation-passing style 을 일반적으로 사용했습니다. SSA 는 공식적으로는, 중간 표현으로서 사용될 때는 발생하지 않는, non-local control flow 를 제외하고는 잘 동작하는( well-behaved ) CPS 의 서브셋과 동일합니다. So optimizations and transformations formulated in terms of one immediately apply to the other.

Benefits

SSA 의 주요한 유용성은 다양한 컴파일러에서의 최적화의 결과를 동시에 단순화하고 증진시킨다는 것입니다. 이는 변수의 속성들을 단순화함으로써 수행됩니다. 예를 들어, 다음 코드 조각을 살펴 봅시다.

y := 1

y := 2

x := y

인간들은 첫 번째 할당이 불필요하며 세 번째 라인에서 사용되고 있는 y 의 값이 두 번째 y 할당에서 온다고 생각할 수 있습니다. 프로그램은 reaching definition analysis 를 수행해야만 이를 결정할 수 있을 겁니다. 하지만 프로그램이 SSA 폼이라면, 이것들은 둘 다 임시적( intermediate )입니다:

y1 := 1

y2 := 2

x1 = y2

SSA 를 사용하거나 매우 강화된 컴파일러 최적화 알고리즘들은 다음과 같습니다 :

Converting to SSA

일반 코드를 SSA 폼으로 변환하는 것은 주로 각각의 할당의 대상을 새로운 변수로 치환하고 각각의 변수의 사용을 그 지점에 도달하는 "버전"의 변수로 치환하는 것입니다. 예를 들어, 다음과 같은 제어 흐름 그래프( control flow graph )를 살펴 봅시다:

"x <-- x - 3" 의 왼쪽에 있는 이름을 변경하고 그 다음에 x 를 사용하는 곳을 그 새로운 이름으로 변경하는 것은 프로그램을 수정하지 않고 종료될 수 있게 할 것입니다. 이것은 SSA 에서 새로운 두 개의 변수들을 생성함으로써 이용될 수 있습니다 : x1, x2. 각각의 변수들은 한 번만 할당됩니다. 이런식으로 차이가 나는 서브스크립트를 제공함으로써 다른 변수들이 만들어집니다:

각각이 사용하는 정의가 무엇을 참조하고 있는지는 명확합니다. 한 가지 경우만을 제외하고는 말이죠: 바닥에 있는 블락에서 y 의 사용은 y1 이나 y2 를 가리킬 수 있으며, 이는 제어 흐름이 타고 왔느냐에 의존합니다.

이를 해결하기 위해서, 마지막 블락에 특별한 구문이 삽입되는데, 이를 파이( Φ, Phi ) 함수라고 부릅니다. 이 구문은 y3 라 불리는 새로운 y 에 대한 정의를 생성하는데, 이는 y1 이나 y2 에 의해 선택됨으로써 생성되고, 과거의 제어 흐름에 의존됩니다.

이제 마지막 블락에서는 단순히 y3 를 사용하며 정확한 값은 두 가지 방식으로 획득될 것입니다. x 에 대한 Φ  함수는 불필요합니다: 한 가지 버전의 x 만이 존재하며, 여기에는 x2 가 도달하고 있습니다. 그래서 문제가 없습니다( 다시 말해, Φ ( x2, x2 ) = x2 입니다 ).

주어진 임의의 제어 흐름 그래프에서, 어디에 Φ  함수가 삽입되어야 하며 그것을 위한 변수가 무엇인지를 이야기하는 것은 어려울 수 있습니다. 이러한 범용적인 문제는 ( 아래에 나오는 ) dominance frontiers 라 불리는 개념을 사용해서 계산될 수 있는 효율적인 해를 가지고 있습니다.

Φ  함수는 거의 대부분의 머신에서 머신 연산으로서 구현되지는 않습니다. 컴파일러가, Φ  함수를 메모리의 같은 위치( 혹은 같은 레지스터 )를 Φ  함수의 입력으로 산출하는 모든 연산을 위한 목적지로서 사용함으로써, Φ  함수를 간단하게 구현할 수 있습니다. 그러나 이러한 접근법은, wide-issue 머신에서 발생할 수 있는 것처럼, 동시적 연산들이 추측에 근거해( speculatively ) Φ  함수의 입력을 산출하고 있을 때는 사용할 수 없습니다. 일반적으로 wide-issue 머신은, Φ  함수를 구현하기 위해서, 그러한 상황들에서 사용되는 컴파일러에 의해 제공되는 선택 명령을 가지고 있습니다.

Kenny Zadeck 에 의하면 Φ  함수들은 SSA 가 IBM 연구소에서 1980 년대에 개발되는 도중에는 원래 phony 함수들이었다고 합니다. Φ  함수의 공식적인 이름은 학술 논문에서 처음 출판될 때 적용되었다고 합니다.

[ 하략 ... 원문( Static single assignment form, Wikipedia. ) 을 참조하세요 ].

+ Recent posts