├── .gitignore ├── Dockerfile ├── LICENSE.md ├── Makefile ├── README.md ├── _original_post ├── Mapping-High-Level-Constructs-to-LLVM-IR.page ├── README.md └── convert.py ├── a-quick-primer └── index.rst ├── advanced-constructs ├── closures.rst ├── generators.rst ├── index.rst ├── lambda-functions.rst └── listings │ ├── Makefile │ ├── lambda_func_0.cpp │ ├── lambda_func_0_cleaned.ll │ ├── lambda_func_1.cpp │ ├── lambda_func_1_cleaned.ll │ ├── listing_4.cpp │ ├── listing_5.ll │ ├── listing_6.cpp │ └── listing_7.ll ├── appendix-a-how-to-implement-a-string-type-in-llvm ├── index.rst └── listings │ └── listing_0.ll ├── basic-constructs ├── casts.rst ├── constants.rst ├── functions.rst ├── global-variables.rst ├── index.rst ├── listings │ ├── .gitignore │ ├── Makefile │ ├── cpp_variant.cpp │ ├── function_overloading.cpp │ ├── listing_0.cpp │ ├── listing_1.ll │ ├── listing_10.cpp │ ├── listing_11.ll │ ├── listing_12.ll │ ├── listing_13.ll │ ├── listing_14.cpp │ ├── listing_15.ll │ ├── listing_16.cpp │ ├── listing_17.ll │ ├── listing_18.cpp │ ├── listing_19.ll │ ├── listing_2.ll │ ├── listing_20.ll │ ├── listing_21.ll │ ├── listing_22.cpp │ ├── listing_23.ll │ ├── listing_24.ll │ ├── listing_25.cpp │ ├── listing_26.ll │ ├── listing_27.cpp │ ├── listing_28.ll │ ├── listing_29.ll │ ├── listing_3.ll │ ├── listing_30.cpp │ ├── listing_31.ll │ ├── listing_32.ll │ ├── listing_4.ll │ ├── listing_5.ll │ ├── listing_6.ll │ ├── listing_7.cpp │ ├── listing_8.ll │ ├── listing_9.ll │ ├── rust_enum.ll │ ├── rust_enum.rs │ ├── struct_by_val.cpp │ ├── struct_member_access.cpp │ ├── struct_member_access_cleaned.ll │ └── struct_member_access_old.ll ├── local-variables.rst ├── structures.rst └── unions.rst ├── common.mk ├── conf.py ├── control-structures ├── if-then-else.rst ├── index.rst ├── listings │ ├── Makefile │ ├── simple_if_max.cpp │ ├── simple_if_max_O1_cleaned.ll │ ├── simple_if_max_cleaned.ll │ ├── simple_if_max_cleaned_cfg.png │ └── simple_if_max_phi.ll └── ssa-phi.rst ├── epilogue ├── contribution.rst ├── index.rst └── resources.rst ├── exception-handling ├── exception-handling-by-propagated-return-value.rst ├── index.rst ├── listings │ ├── exception_example.cpp │ ├── propagated_return_values.ll │ └── setjmp_longjmp.ll ├── resources.rst ├── setjmp+longjmp-exception-handling.rst └── zero-cost-exception-handling.rst ├── index.rst ├── interfacing-to-the-operating-system ├── index.rst └── listings │ ├── listing_0.ll │ └── windows.ll ├── interoperating-with-a-runtime-library └── index.rst ├── make.bat └── object-oriented-constructs ├── boxing-and-unboxing.rst ├── class-equivalence-test.rst ├── class-inheritance-test.rst ├── classes.rst ├── index.rst ├── interfaces.rst ├── listings ├── listing_0.cpp ├── listing_1.ll ├── listing_10.cpp ├── listing_11.cpp ├── listing_11.ll ├── listing_12.cpp ├── listing_12.ll ├── listing_13.cpp ├── listing_13.ll ├── listing_14.ll ├── listing_15.ll ├── listing_2.cpp ├── listing_3.cpp ├── listing_3.ll ├── listing_4.cpp ├── listing_4.ll ├── listing_5.cpp ├── listing_5.ll ├── listing_6.cpp ├── listing_6.ll ├── listing_7.cpp ├── listing_7.ll ├── listing_8.cpp ├── listing_8.ll ├── listing_9.cpp └── listing_9.ll ├── multiple-inheritance.rst ├── single-inheritance.rst ├── the-new-operator.rst ├── virtual-inheritance.rst └── virtual-methods.rst /.gitignore: -------------------------------------------------------------------------------- 1 | _build/ 2 | 3 | # Node rules: 4 | ## Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 5 | .grunt 6 | 7 | ## Dependency directory 8 | ## Commenting this out is preferred by some people, see 9 | ## https://docs.npmjs.com/misc/faq#should-i-check-my-node_modules-folder-into-git 10 | node_modules 11 | 12 | # Book build output 13 | _book 14 | 15 | # eBook build output 16 | *.epub 17 | *.mobi 18 | *.pdf 19 | 20 | ################################# 21 | # https://github.com/github/gitignore/blob/master/Python.gitignore 22 | ################################# 23 | # Byte-compiled / optimized / DLL files 24 | __pycache__/ 25 | *.py[cod] 26 | *$py.class 27 | 28 | # C extensions 29 | *.so 30 | 31 | # Distribution / packaging 32 | .Python 33 | build/ 34 | develop-eggs/ 35 | dist/ 36 | downloads/ 37 | eggs/ 38 | .eggs/ 39 | lib/ 40 | lib64/ 41 | parts/ 42 | sdist/ 43 | var/ 44 | wheels/ 45 | *.egg-info/ 46 | .installed.cfg 47 | *.egg 48 | MANIFEST 49 | 50 | # PyInstaller 51 | # Usually these files are written by a python script from a template 52 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 53 | *.manifest 54 | *.spec 55 | 56 | # Installer logs 57 | pip-log.txt 58 | pip-delete-this-directory.txt 59 | 60 | # Unit test / coverage reports 61 | htmlcov/ 62 | .tox/ 63 | .coverage 64 | .coverage.* 65 | .cache 66 | nosetests.xml 67 | coverage.xml 68 | *.cover 69 | .hypothesis/ 70 | .pytest_cache/ 71 | 72 | # Translations 73 | *.mo 74 | *.pot 75 | 76 | # Django stuff: 77 | *.log 78 | local_settings.py 79 | db.sqlite3 80 | 81 | # Flask stuff: 82 | instance/ 83 | .webassets-cache 84 | 85 | # Scrapy stuff: 86 | .scrapy 87 | 88 | # Sphinx documentation 89 | docs/_build/ 90 | 91 | # PyBuilder 92 | target/ 93 | 94 | # Jupyter Notebook 95 | .ipynb_checkpoints 96 | 97 | # pyenv 98 | .python-version 99 | 100 | # celery beat schedule file 101 | celerybeat-schedule 102 | 103 | # SageMath parsed files 104 | *.sage.py 105 | 106 | # Environments 107 | .env 108 | .venv 109 | env/ 110 | venv/ 111 | ENV/ 112 | env.bak/ 113 | venv.bak/ 114 | 115 | # Spyder project settings 116 | .spyderproject 117 | .spyproject 118 | 119 | # Rope project settings 120 | .ropeproject 121 | 122 | # mkdocs documentation 123 | /site 124 | 125 | # mypy 126 | .mypy_cache/ 127 | ################################# 128 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:rolling 2 | 3 | WORKDIR /app 4 | 5 | # Set these using: docker build --build-arg NATIVE_UID=$(id -u ${USER}) --build-arg NATIVE_GID=$(id -g ${USER}) -t llvmir . 6 | ARG NATIVE_UID=1000 7 | ARG NATIVE_GID=1000 8 | 9 | # The default user created by ubuntu:rolling is ubuntu(1000):ubuntu(1000), which we'll reuse. 10 | ARG DOCKER_UID=ubuntu 11 | ARG DOCKER_GID=ubuntu 12 | 13 | # Recreate docker user:group as our host user:group (to avoid getting output files owned by root). 14 | # See https://jtreminio.com/blog/running-docker-containers-as-current-host-user/ for more information. 15 | RUN \ 16 | if [ ${NATIVE_UID:-0} -ne 0 ] && [ ${NATIVE_GID:-0} -ne 0 ]; then \ 17 | userdel -f ${DOCKER_UID} &&\ 18 | if getent group ${DOCKER_GID}; then groupdel ${DOCKER_GID}; fi &&\ 19 | groupadd -g ${NATIVE_GID} ${DOCKER_GID} &&\ 20 | useradd -l -u ${NATIVE_GID} -g ${DOCKER_GID} ${DOCKER_GID} &&\ 21 | install -d -m 0755 -o ${DOCKER_UID} -g ${DOCKER_GID} /app/_build &&\ 22 | chown --changes --silent --no-dereference --recursive --from=`id -u ${DOCKER_UID}`:`id -g ${DOCKER_GID}` ${NATIVE_UID}:${NATIVE_GID} /app/_build \ 23 | ;fi 24 | 25 | # Disable interactive features in Debian `apt` and `apt-get` tools. 26 | ARG DEBIAN_FRONTEND=noninteractive 27 | 28 | # Install the things that we actually need. 29 | RUN \ 30 | apt-get update &&\ 31 | apt-get install --no-install-recommends -q -y make python3-sphinx python3-sphinx-rtd-theme &&\ 32 | bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" &&\ 33 | apt-get clean -y &&\ 34 | rm -rf /var/lib/apt/lists/* 35 | 36 | USER ${DOCKER_UID}:${DOCKER_GID} 37 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | 3 | # NOTE: You must either add the current user to the docker group (insecure) 4 | # NOTE: or use 'sudo' as a prefix to make when you invoke any of the docker-* 5 | # NOTE: commands. 6 | 7 | # You can set these variables from the command line. 8 | SPHINXOPTS = 9 | SPHINXBUILD = sphinx-build 10 | SPHINXPROJ = MappingHighLevelConstructstoLLVMIR 11 | SOURCEDIR = . 12 | BUILDDIR = _build 13 | 14 | # Put it first so that "make" without argument is like "make help". 15 | help: 16 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 17 | 18 | .PHONY: help Makefile 19 | 20 | # Catch-all target: route all unknown targets to Sphinx using the new 21 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 22 | %: Makefile 23 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 24 | 25 | # Build a new docker container with the name 'llvm-ir'. 26 | docker-build: 27 | # NOTE: The command below requires sudo: sudo make docker-build 28 | docker build --build-arg=NATIVE_UID=$(id -u ${USER}) --build-arg=NATIVE_GID=$(id -g ${USER}) -t llvm-ir . 29 | 30 | # Run Sphinx inside the docker container. 31 | docker-make: 32 | # NOTE: The command below requires sudo: sudo make docker-make O=html 33 | docker run -w /app --mount type=bind,src="$(shell pwd)",target=/app llvm-ir sh -c "make $(SPHINXOPTS) $(O)" 34 | 35 | # Run a command in the app folder inside the docker container. 36 | docker-run: 37 | # NOTE: The command below requires sudo: sudo make docker-run O="ls -l" 38 | docker run --rm --interactive --tty --volume $(shell pwd):/app llvm-ir $(O) 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Mapping High Level Constructs to LLVM IR 2 | 3 | ## About 4 | This is a gitbook dedicated to providing a description on how LLVM based 5 | compilers map high-level language constructs into the LLVM intermediate 6 | representation (IR). 7 | 8 | This document targets people interested in how modern compilers work and 9 | want to learn how high-level language constructs can be implemented. 10 | Currently the books focuses on C and C++, but contributions about other 11 | languages targeting LLVM are highly welcome. This document should help 12 | to make the learning curve less steep for aspiring LLVM users. 13 | 14 | For the sake of simplicity, we'll be working with a 32-bit target 15 | machine so that pointers and word-sized operands are 32-bits. Also, for 16 | the sake of readability we do not mangle (encode) names. Rather, they 17 | are given simple, easy-to-read names that reflect their purpose. A 18 | production compiler for any language that supports overloading would 19 | generally need to mangle the names so as to avoid conflicts between 20 | symbols. 21 | 22 | ## Reading the Book 23 | Read the book online at [ReadTheDocs](https://mapping-high-level-constructs-to-llvm-ir.rtfd.io/). 24 | 25 | ## Relevant External Resources on LLVM IR 26 | This section presents various external links of relevance to those studying LLVM IR: 27 | 28 | * [Getting Started / Tutorials](https://llvm.org/docs/GettingStartedTutorials.html) 29 | * [A Gentle Introduction to LLVM IR](https://mcyoung.xyz/2023/08/01/llvm-ir/) 30 | * [Mapping Python to LLVM IR](https://blog.exaloop.io/python-llvm/) 31 | 32 | If you have other relevant links, please open an issue or submit a pull request with the link added to the list above. 33 | 34 | ## Contributing 35 | All contributions are welcome! 36 | 37 | The repository is on [GitHub](https://github.com/f0rki/mapping-high-level-constructs-to-llvm-ir). 38 | 39 | If you find an error, [file an issue](https://github.com/f0rki/mapping-high-level-constructs-to-llvm-ir/issues) 40 | or [create a pull request](https://github.com/f0rki/mapping-high-level-constructs-to-llvm-ir/pulls). 41 | 42 | ## Building 43 | You can build the book in one of two ways: Using Ubuntu Linux or Docker on Linux. 44 | 45 | ### Fetching the Project 46 | 1. Change to your home directory: `cd ~` 47 | 2. Clone the repository: `git clone https://github.com/f0rki/mapping-high-level-constructs-to-llvm-ir llvm-ir` 48 | 3. Enter the project directory: `cd llvm-ir` 49 | 50 | ### Setting Up Ubuntu Linux 51 | 1. Install Make and some friends (~244 MB): `sudo apt install -y build-essential` 52 | 2. Install the Python pip tool (~38 MB): `sudo apt install -y python3-pip` 53 | 3. Install Sphinx for Python (~15 MB): `sudo apt install -y python3-sphinx` 54 | 4. Install ReadTheDocs theme for Sphinx (~15 MB): `sudo apt install -y python3-sphinx-rtd-theme` 55 | 56 | You can now build the documentation locally: 57 | 58 | 5. Build the documentation locally: `make html`. 59 | 6. You can now browse the documentation in the `_build/html` folder. 60 | 61 | ### Building using Docker 62 | 1. [Install Docker](https://docs.docker.com/engine/install/ubuntu/#install-using-the-repository). 63 | DO NOT INSTALL USING THE STANDARD UBUNTU REPOSITORIES. IT WON'T WORK! 64 | 2. Create the docker image: `sudo make docker-build`. 65 | 3. Make the book: `sudo make docker-make O=html`. 66 | 4. The book can now be found in the `_build/html` folder. 67 | 68 | ## License 69 | UNLESS OTHERWISE NOTED, THE CONTENTS OF THIS REPOSITORY/DOCUMENT ARE LICENSED 70 | UNDER THE CREATIVE COMMONS ATTRIBUTION - SHARE ALIKE 4.0 INTERNATIONAL LICENSE 71 | -------------------------------------------------------------------------------- /_original_post/README.md: -------------------------------------------------------------------------------- 1 | This directory contains the original post, published in a custom markdown 2 | language. This was converted into markdown using the `convert.py` script. 3 | -------------------------------------------------------------------------------- /_original_post/convert.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import re 5 | import errno 6 | 7 | 8 | # programming by stackoverflow: http://stackoverflow.com/questions/600268/mkdir-p-functionality-in-python#600612 9 | def mkdir_p(path): 10 | try: 11 | os.makedirs(path) 12 | except OSError as exc: 13 | if exc.errno == errno.EEXIST and os.path.isdir(path): 14 | pass 15 | else: 16 | raise 17 | 18 | 19 | src_ext_map = {"LLVM": "ll", "C": "c", "C++": "cpp"} 20 | 21 | class LineBuffer: 22 | 23 | def __init__(self, fileobj): 24 | self.file = fileobj 25 | self._iter = iter(self.file.readlines()) 26 | self.buf = [] 27 | self.num = 0 28 | self._iter_empty = False 29 | 30 | @property 31 | def has_next(self): 32 | return (not self._iter_empty) or self.buf 33 | 34 | def next(self): 35 | if self.buf: 36 | line = self.buf.pop() 37 | else: 38 | if self._iter_empty: 39 | raise StopIteration() 40 | try: 41 | line = self._iter.__next__() 42 | except StopIteration: 43 | self._iter_empty = True 44 | raise 45 | self.num += 1 46 | return (self.num, line) 47 | 48 | __next__ = next 49 | 50 | def put_back(self, line): 51 | self.num -= 1 52 | self.buf.append(line) 53 | 54 | def __iter__(self): 55 | return self 56 | 57 | def destroy(self): 58 | self.file.close() 59 | self._iter = None 60 | self.buf = [] 61 | self.num = -1 62 | self._iter_empty = True 63 | 64 | 65 | def space_to_dash(s): 66 | s = s.lower() 67 | return re.sub(r"\s+", "-", s) 68 | 69 | 70 | class Converter: 71 | 72 | def __init__(self, infile, outdir): 73 | self.infile = infile 74 | self.outdir = outdir 75 | self.current_chapter = None 76 | self.current_section = None 77 | self.curof = None 78 | self.current_line = -1 79 | self.current_listing = 0 80 | 81 | def __enter__(self): 82 | self.curof = open(os.path.join(self.outdir, "README.md"), "w") 83 | self.summaryf = open(os.path.join(self.outdir, "SUMMARY.md"), "w") 84 | self.todof = open(os.path.join(self.outdir, "TODOS.md"), "w") 85 | self.inp = LineBuffer(self.infile) 86 | return self 87 | 88 | def __exit__(self, type, value, traceback): 89 | self.curof.close() 90 | self.summaryf.close() 91 | self.todof.close() 92 | self.inp.destroy() 93 | return False 94 | 95 | def convert_to_md(self): 96 | self.summaryf.write("# Summary\n\n") 97 | 98 | for i, line in self.inp: 99 | self.current_line = i 100 | if line.startswith("!"): 101 | s = line.split(" ") 102 | cmd, args = s[0], " ".join(s[1:]) 103 | self.handle_cmd(cmd, args) 104 | elif line.startswith("{todo"): 105 | self.handle_todo(line) 106 | elif "!format" in line: 107 | self.handle_code_listing(line) 108 | else: 109 | self.process_line(line) 110 | 111 | # self.summaryf.write("* [TODO List](TODOS.md)") 112 | 113 | def convert_line(self, line): 114 | line = re.sub(r"{c:([^}]+)}", r"`\1`", line) 115 | line = re.sub(r"{b:([^}]+)}", r"**\1**", line) 116 | line = re.sub(r"{i:([^}]+)}", r"*\1*", line) 117 | line = re.sub(r"{link:([^|]+)\|([^}]+)}", 118 | r"[\2](\1)", line) 119 | line = re.sub(r"{mail:([^|]+)\|([^}]+)}", 120 | r"[\2](mailto:\1)", line) 121 | line = line.replace("#", "-") 122 | return line 123 | 124 | def process_line(self, line): 125 | line = self.convert_line(line) 126 | self.curof.write(line) 127 | 128 | def handle_todo(self, line): 129 | line = re.sub(r"{todo:([^}]+)}", r"\1", line).strip() 130 | 131 | if self.current_section: 132 | link = "[{}]({}/{}.md)".format(self.current_section, 133 | self.current_chapter, 134 | self.current_section) 135 | else: 136 | link = "[{}]({}/{}.md)".format(self.current_chapter, 137 | self.current_chapter, 138 | "README") 139 | 140 | self.todof.write("- [ ] in {}: {}\n" 141 | .format(link, self.convert_line(line))) 142 | 143 | def switch_file(self, newfile, subdir=None): 144 | if subdir is None: 145 | fname = os.path.join(self.outdir, newfile) 146 | else: 147 | realdir = os.path.join(self.outdir, subdir) 148 | if not os.path.exists(realdir): 149 | mkdir_p(realdir) 150 | fname = os.path.join(realdir, newfile) 151 | self.curof.close() 152 | self.curof = open(fname, "w") 153 | 154 | def handle_code_listing(self, line): 155 | _, srcfmt = line.strip().split() 156 | extension = src_ext_map[srcfmt] 157 | realdir = os.path.join(self.outdir, 158 | self.current_chapter, 159 | "listings") 160 | if not os.path.exists(realdir): 161 | mkdir_p(realdir) 162 | sourcefname = os.path.join(realdir, 163 | "listing_{}.{}" 164 | .format(self.current_listing, 165 | extension)) 166 | sourcef = open(sourcefname, "w") 167 | self.current_listing += 1 168 | 169 | def write(what): 170 | self.curof.write(what) 171 | sourcef.write(what) 172 | 173 | self.curof.write("```" + extension + "\n") 174 | lastwasempty = False 175 | while self.inp.has_next: 176 | i, line = self.inp.next() 177 | if line.strip() == "": 178 | lastwasempty = True 179 | continue 180 | if line[0] == "\t" and "!format" not in line: 181 | if lastwasempty: 182 | write("\n") 183 | write(line[1:]) 184 | lastwasempty = False 185 | else: 186 | break 187 | self.curof.write("```\n\n") 188 | if lastwasempty: 189 | self.inp.put_back("\n") 190 | 191 | self.inp.put_back(line) 192 | 193 | sourcef.close() 194 | 195 | def handle_cmd(self, cmd, args): 196 | if cmd == "!chapter": 197 | self.info("processing chapter", args) 198 | chaptername = args.strip() 199 | self.current_chapter = (space_to_dash(chaptername.strip()) 200 | .replace("/", "+") 201 | .replace(":", "")) 202 | self.current_section = "" 203 | self.switch_file("README.md", self.current_chapter) 204 | self.current_listing = 0 205 | self.curof.write("# {}\n".format(args)) 206 | 207 | self.summaryf.write("* [{}]({}/README.md)\n" 208 | .format(chaptername, 209 | self.current_chapter)) 210 | elif cmd == "!section": 211 | self.info("processing section", args, "in", self.current_chapter) 212 | sectionname = args.strip() 213 | self.current_section = (space_to_dash(sectionname) 214 | .replace("/", "+")) 215 | self.switch_file(self.current_section + ".md", 216 | self.current_chapter) 217 | self.curof.write("## {}\n".format(sectionname)) 218 | self.curof.write("\n\n") 219 | 220 | self.summaryf.write(" * [{}]({}/{}.md)\n" 221 | .format(sectionname, 222 | self.current_chapter, 223 | self.current_section)) 224 | elif cmd == "!subsection": 225 | self.curof.write("### {}\n".format(args)) 226 | else: 227 | self.warn("unknown command '{}'".format(cmd)) 228 | # self.curof.write("`{} {}`".format(cmd, args)) 229 | 230 | def warn(self, *args): 231 | s = " ".join(map(lambda x: str(x).strip(), args)) 232 | print("\x1b[93;41mWARNING\x1b[0m (line {}): {}" 233 | .format(self.current_line, s)) 234 | 235 | def info(self, *args): 236 | s = " ".join(map(lambda x: str(x).strip(), args)) 237 | print("info (line {}): {}".format(self.current_line, s)) 238 | 239 | 240 | if __name__ == "__main__": 241 | origfile = "./Mapping-High-Level-Constructs-to-LLVM-IR.page" 242 | with open(origfile) as f: 243 | with Converter(f, "..") as conv: 244 | conv.convert_to_md() 245 | -------------------------------------------------------------------------------- /a-quick-primer/index.rst: -------------------------------------------------------------------------------- 1 | ************** 2 | A Quick Primer 3 | ************** 4 | 5 | Here are a few things that you should know before reading this document: 6 | 7 | - LLVM IR is not machine code, but sort of the step just above assembly. So 8 | some things look more like a high-level language (like functions and the 9 | strong typing). Other looks more like low-level assembly (e.g. branching, 10 | basic-blocks). 11 | - LLVM IR is strongly typed so expect to be told when you do something wrong. 12 | - LLVM IR does not differentiate between signed and unsigned integers. 13 | - LLVM IR assumes two's complement signed integers so that say ``trunc`` works 14 | equally well on signed and unsigned integers. 15 | - Global symbols begin with an at sign (``@``). 16 | - Local symbols begin with a percent symbol (``%``). 17 | - All symbols must be declared or defined. 18 | - Don't worry that the LLVM IR at times can seem somewhat lengthy when it comes 19 | to expressing something; the optimizer will ensure the output is well 20 | optimized and you'll often see two or three LLVM IR instructions be coalesced 21 | into a single machine code instruction. 22 | - If in doubt, consult the Language Reference [#langref]_. If there is a 23 | conflict between the Language Reference and this document, this document is 24 | wrong! Please file an issue on github then. 25 | - All LLVM IR examples are presented without a data layout and without a target 26 | triple. You can assume it's usually x86 or x86_64. 27 | - The original version of this document was written a while ago, therefore some 28 | of the snippets of LLVM IR might not compile anymore with the most recent 29 | LLVM/clang version. Please file a bug report at github if you encounter such 30 | a case. 31 | 32 | Some Useful LLVM Tools 33 | ---------------------- 34 | 35 | The most important LLVM tools for use with this article are as follows: 36 | 37 | +----------------+----------------+---------------+-----------+---------------------+ 38 | | Name | Function | Reads | Writes | Arguments | 39 | +================+================+===============+===========+=====================+ 40 | | ``clang`` | C Compiler | ``.c`` | ``.ll`` | ``-emit-llvm -S`` | 41 | +----------------+----------------+---------------+-----------+---------------------+ 42 | | ``clang++`` | C++ Compiler | ``.cpp`` | ``.ll`` | ``-emit-llvm -S`` | 43 | +----------------+----------------+---------------+-----------+---------------------+ 44 | | ``opt`` | Optimizer | ``.bc/.ll`` | ``.bc`` | | 45 | +----------------+----------------+---------------+-----------+---------------------+ 46 | | ``llvm-dis`` | Disassembler | ``.bc`` | ``.ll`` | | 47 | +----------------+----------------+---------------+-----------+---------------------+ 48 | | ``llc`` | IR Compiler | ``.ll`` | ``.s`` | | 49 | +----------------+----------------+---------------+-----------+---------------------+ 50 | 51 | While you are playing around with generating or writing LLVM IR, you may 52 | want to add the option ``-fsanitize=undefined`` to Clang/Clang++ insofar 53 | you use either of those. This option makes Clang/Clang++ insert run-time 54 | checks in places where it would normally output an ``ud2`` instruction. 55 | This will likely save you some trouble if you happen to generate 56 | undefined LLVM IR. Please notice that this option only works for C and 57 | C++ compilers. 58 | 59 | Note that you can use ``.ll`` or ``.bc`` files as input files for 60 | ``clang(++)`` and compile full executables from bitcode files. 61 | 62 | 63 | .. [#langref] http://llvm.org/docs/LangRef.html 64 | -------------------------------------------------------------------------------- /advanced-constructs/closures.rst: -------------------------------------------------------------------------------- 1 | Closures 2 | -------- 3 | -------------------------------------------------------------------------------- /advanced-constructs/generators.rst: -------------------------------------------------------------------------------- 1 | Generators 2 | ---------- 3 | 4 | A generator is a function that repeatedly yields a value in such a way 5 | that the function's state is preserved across the repeated calls of the 6 | function; this includes the function's local offset at the point it 7 | yielded a value. 8 | 9 | The most straightforward way to implement a generator is by wrapping all 10 | of its state variables (arguments, local variables, and return values) 11 | up into an ad-hoc structure and then pass the address of that structure 12 | to the generator. 13 | 14 | Somehow, you need to keep track of which block of the generator you are 15 | doing on each call. This can be done in various ways; the way we show 16 | here is by using LLVM's ``blockaddress`` instruction to save the address 17 | of the next local block of code that should be executed. Other 18 | implementations use a simple state variable and then do a 19 | ``switch``-like dispatch according to the value of the state variable. 20 | In both cases, the end result is the same: A different block of code is 21 | executed for each local block in the generator. 22 | 23 | The important thing is to think of iterators as a sort of micro-thread 24 | that is resumed whenever the iterator is called again. In other words, 25 | we need to save the address of how far the iterator got on each pass 26 | through so that it can resume as if a microscopic thread switch had 27 | occurred. So we save the address of the instruction after the return 28 | instruction so that we can resume running as if we never had returned in 29 | the first place. 30 | 31 | I resort to pseudo-C++ because C++ does not directly support generators. 32 | First we look at a very simple case then we advance on to a slightly 33 | more complex case: 34 | 35 | .. code-block:: cpp 36 | 37 | #include 38 | 39 | generator int foo() 40 | { 41 | yield 1; 42 | yield 2; 43 | yield 3; 44 | } 45 | 46 | int main() 47 | { 48 | foreach (int i in foo()) 49 | printf("Value: %d\n", i); 50 | 51 | return 0; 52 | } 53 | 54 | This becomes: 55 | 56 | ; Compiled and run successfully against LLVM v3.4 on 2013.12.06. 57 | 58 | .. code-block:: llvm 59 | 60 | %foo_context = type { 61 | i8*, ; 0: block (state) 62 | i32 ; 1: value (result) 63 | } 64 | 65 | define void @foo_setup(%foo_context* %context) nounwind { 66 | ; set up 'block' 67 | %1 = getelementptr %foo_context* %context, i32 0, i32 0 68 | store i8* blockaddress(@foo_yield, %.yield1), i8** %1 69 | 70 | ret void 71 | } 72 | 73 | ; The boolean returned indicates if a result was available or not. 74 | ; Once no more results are available, the caller is expected to not call 75 | ; the iterator again. 76 | define i1 @foo_yield(%foo_context* %context) nounwind { 77 | ; dispatch to the active generator block 78 | %1 = getelementptr %foo_context* %context, i32 0, i32 0 79 | %2 = load i8** %1 80 | indirectbr i8* %2, [ label %.yield1, label %.yield2, label %.yield3, label %.done ] 81 | 82 | .yield1: 83 | ; store the result value (1) 84 | %3 = getelementptr %foo_context* %context, i32 0, i32 1 85 | store i32 1, i32* %3 86 | 87 | ; make 'block' point to next block to execute 88 | %4 = getelementptr %foo_context* %context, i32 0, i32 0 89 | store i8* blockaddress(@foo_yield, %.yield2), i8** %4 90 | 91 | ret i1 1 92 | 93 | .yield2: 94 | ; store the result value (2) 95 | %5 = getelementptr %foo_context* %context, i32 0, i32 1 96 | store i32 2, i32* %5 97 | 98 | ; make 'block' point to next block to execute 99 | %6 = getelementptr %foo_context* %context, i32 0, i32 0 100 | store i8* blockaddress(@foo_yield, %.yield3), i8** %6 101 | 102 | ret i1 1 103 | 104 | .yield3: 105 | ; store the result value (3) 106 | %7 = getelementptr %foo_context* %context, i32 0, i32 1 107 | store i32 3, i32* %7 108 | 109 | ; make 'block' point to next block to execute 110 | %8 = getelementptr %foo_context* %context, i32 0, i32 0 111 | store i8* blockaddress(@foo_yield, %.done), i8** %8 112 | 113 | ret i1 1 114 | 115 | .done: 116 | ret i1 0 117 | } 118 | 119 | declare i32 @printf(i8*, ...) nounwind 120 | 121 | @.string = internal constant [11 x i8] c"Value: %d\0A\00" 122 | 123 | define void @main() nounwind { 124 | ; allocate and initialize generator context structure 125 | %context = alloca %foo_context 126 | call void @foo_setup(%foo_context* %context) 127 | br label %.head 128 | 129 | .head: 130 | ; foreach (int i in foo()) 131 | %1 = call i1 @foo_yield(%foo_context* %context) 132 | br i1 %1, label %.body, label %.tail 133 | 134 | .body: 135 | %2 = getelementptr %foo_context* %context, i32 0, i32 1 136 | %3 = load i32* %2 137 | %4 = call i32 (i8*, ...)* @printf(i8* getelementptr([11 x i8]* @.string, i32 0, i32 0), i32 %3) 138 | br label %.head 139 | 140 | .tail: 141 | ret void 142 | } 143 | 144 | And now for a slightly more complex example that involves local 145 | variables: 146 | 147 | .. code-block:: cpp 148 | 149 | #include 150 | 151 | generator int foo(int start, int after) 152 | { 153 | for (int index = start; index < after; index++) 154 | { 155 | if (index % 2 == 0) 156 | yield index + 1; 157 | else 158 | yield index - 1; 159 | } 160 | } 161 | 162 | int main(void) 163 | { 164 | foreach (int i in foo(0, 5)) 165 | printf("Value: %d\n", i); 166 | 167 | return 0; 168 | } 169 | 170 | This becomes something like this: 171 | 172 | ; Compiled and run successfully against LLVM v3.4 on 2013.12.06. 173 | 174 | .. code-block:: llvm 175 | 176 | %foo_context = type { 177 | i8*, ; 0: block (state) 178 | i32, ; 1: start (argument) 179 | i32, ; 2: after (argument) 180 | i32, ; 3: index (local) 181 | i32 ; 4: value (result) 182 | } 183 | 184 | define void @foo_setup(%foo_context* %context, i32 %start, i32 %after) nounwind { 185 | ; set up 'block' 186 | %1 = getelementptr %foo_context* %context, i32 0, i32 0 187 | store i8* blockaddress(@foo_yield, %.init), i8** %1 188 | 189 | ; set up 'start' 190 | %2 = getelementptr %foo_context* %context, i32 0, i32 1 191 | store i32 %start, i32* %2 192 | 193 | ; set up 'after' 194 | %3 = getelementptr %foo_context* %context, i32 0, i32 2 195 | store i32 %after, i32* %3 196 | 197 | ret void 198 | } 199 | 200 | define i1 @foo_yield(%foo_context* %context) nounwind { 201 | ; dispatch to the active generator block 202 | %1 = getelementptr %foo_context* %context, i32 0, i32 0 203 | %2 = load i8** %1 204 | indirectbr i8* %2, [ label %.init, label %.loop_close, label %.end ] 205 | 206 | .init: 207 | ; copy argument 'start' to the local variable 'index' 208 | %3 = getelementptr %foo_context* %context, i32 0, i32 1 209 | %start = load i32* %3 210 | %4 = getelementptr %foo_context* %context, i32 0, i32 3 211 | store i32 %start, i32* %4 212 | br label %.head 213 | 214 | .head: 215 | ; for (; index < after; ) 216 | %5 = getelementptr %foo_context* %context, i32 0, i32 3 217 | %index = load i32* %5 218 | %6 = getelementptr %foo_context* %context, i32 0, i32 2 219 | %after = load i32* %6 220 | %again = icmp slt i32 %index, %after 221 | br i1 %again, label %.loop_begin, label %.exit 222 | 223 | .loop_begin: 224 | %7 = srem i32 %index, 2 225 | %8 = icmp eq i32 %7, 0 226 | br i1 %8, label %.even, label %.odd 227 | 228 | .even: 229 | ; store 'index + 1' in 'value' 230 | %9 = add i32 %index, 1 231 | %10 = getelementptr %foo_context* %context, i32 0, i32 4 232 | store i32 %9, i32* %10 233 | 234 | ; make 'block' point to the end of the loop (after the yield) 235 | %11 = getelementptr %foo_context* %context, i32 0, i32 0 236 | store i8* blockaddress(@foo_yield, %.loop_close), i8** %11 237 | 238 | ret i1 1 239 | 240 | .odd: 241 | ; store 'index - 1' in value 242 | %12 = sub i32 %index, 1 243 | %13 = getelementptr %foo_context* %context, i32 0, i32 4 244 | store i32 %12, i32* %13 245 | 246 | ; make 'block' point to the end of the loop (after the yield) 247 | %14 = getelementptr %foo_context* %context, i32 0, i32 0 248 | store i8* blockaddress(@foo_yield, %.loop_close), i8** %14 249 | 250 | ret i1 1 251 | 252 | .loop_close: 253 | ; increment 'index' 254 | %15 = getelementptr %foo_context* %context, i32 0, i32 3 255 | %16 = load i32* %15 256 | %17 = add i32 %16, 1 257 | store i32 %17, i32* %15 258 | br label %.head 259 | 260 | .exit: 261 | ; make 'block' point to the %.end label 262 | %x = getelementptr %foo_context* %context, i32 0, i32 0 263 | store i8* blockaddress(@foo_yield, %.end), i8** %x 264 | br label %.end 265 | 266 | .end: 267 | ret i1 0 268 | } 269 | 270 | declare i32 @printf(i8*, ...) nounwind 271 | 272 | @.string = internal constant [11 x i8] c"Value: %d\0A\00" 273 | 274 | define i32 @main() nounwind { 275 | ; allocate and initialize generator context structure 276 | %context = alloca %foo_context 277 | call void @foo_setup(%foo_context* %context, i32 0, i32 5) 278 | br label %.head 279 | 280 | .head: 281 | ; foreach (int i in foo(0, 5)) 282 | %1 = call i1 @foo_yield(%foo_context* %context) 283 | br i1 %1, label %.body, label %.tail 284 | 285 | .body: 286 | %2 = getelementptr %foo_context* %context, i32 0, i32 4 287 | %3 = load i32* %2 288 | %4 = call i32 (i8*, ...)* @printf(i8* getelementptr([11 x i8]* @.string, i32 0, i32 0), i32 %3) 289 | br label %.head 290 | 291 | .tail: 292 | ret i32 0 293 | } 294 | 295 | Another possible way of doing the above would be to generate an LLVM IR 296 | function for each state and then store a function pointer 297 | 298 | in the context structure, which is updated whenever a new state/function 299 | needs to be invoked. 300 | -------------------------------------------------------------------------------- /advanced-constructs/index.rst: -------------------------------------------------------------------------------- 1 | ****************************** 2 | Advanced/Functional Constructs 3 | ****************************** 4 | 5 | In this chapter, we'll look at various non-OOP constructs that are 6 | highly useful and are becoming more and more widespread in use. 7 | 8 | .. toctree:: 9 | :caption: Contents: 10 | 11 | lambda-functions 12 | generators 13 | -------------------------------------------------------------------------------- /advanced-constructs/lambda-functions.rst: -------------------------------------------------------------------------------- 1 | Lambda Functions 2 | ---------------- 3 | 4 | In C++, a lambda function is an anonymous function with the added spice that it may freely refer to 5 | the local variables (including argument variables) in the containing function. Lambdas are 6 | implemented just like Pascal's nested functions, except the compiler is responsible for generating 7 | an internal name for the lambda function. There are a few different ways of implementing lambda 8 | functions (see `Wikipedia on Nested Functions `__ for 9 | more information). The more generalized concept behind this are function closures, i.e., functions 10 | defined within other functions that can also escape the context of the current functions (again 11 | refer to `Wikipedia on Closure `__). 12 | 13 | Closures are common in many modern high-level programming languages, and especially so in functional 14 | programming languages. However, first we take a closer look at how one could implement C++'s lambda 15 | functions. 16 | 17 | .. literalinclude:: listings/lambda_func_0.cpp 18 | :language: c++ 19 | 20 | Here the "problem" is that the lambda function references a local 21 | variable of the caller, namely ``a``, even though the lambda function is 22 | a function of its own. This can be solved easily by passing the local 23 | variable in as an implicit argument to the lambda function: 24 | 25 | 26 | .. literalinclude:: listings/lambda_func_0_cleaned.ll 27 | :language: llvm 28 | 29 | Alternatively, if the lambda function uses more than a few variables, you can wrap them up in a 30 | structure which you pass in a pointer to the lambda function. You will notice that this is actually 31 | the default behavior of clang. 32 | 33 | .. literalinclude:: listings/lambda_func_1.cpp 34 | :language: c++ 35 | 36 | Becomes: 37 | 38 | .. literalinclude:: listings/lambda_func_1_cleaned.ll 39 | :language: llvm 40 | 41 | There are a couple of possible variations over this approach: 42 | 43 | - You could pass all implicit captures as explicit arguments to the function. 44 | - You could pass all implicit captures as explicit arguments in the structure. 45 | - You could pass in a pointer to the frame of the caller and let the 46 | lambda function extract the arguments and locals from the input 47 | frame. 48 | -------------------------------------------------------------------------------- /advanced-constructs/listings/Makefile: -------------------------------------------------------------------------------- 1 | include ../../common.mk 2 | -------------------------------------------------------------------------------- /advanced-constructs/listings/lambda_func_0.cpp: -------------------------------------------------------------------------------- 1 | int foo(int a) 2 | { 3 | auto function = [a](int x) { return x + a; }; 4 | return function(10); 5 | } 6 | -------------------------------------------------------------------------------- /advanced-constructs/listings/lambda_func_0_cleaned.ll: -------------------------------------------------------------------------------- 1 | define internal i32 @lambda(i32 %a, i32 %x) { 2 | %1 = add i32 %a, %x 3 | ret i32 %1 4 | } 5 | 6 | define i32 @foo(i32 %a) { 7 | %1 = call i32 @lambda(i32 %a, i32 10) 8 | ret i32 %1 9 | } 10 | -------------------------------------------------------------------------------- /advanced-constructs/listings/lambda_func_1.cpp: -------------------------------------------------------------------------------- 1 | extern int integer_parse(); 2 | 3 | int foo(int a, int b) 4 | { 5 | int c = integer_parse(); 6 | auto function = [a, b, c](int x) { return (a + b - c) * x; }; 7 | return function(10); 8 | } 9 | -------------------------------------------------------------------------------- /advanced-constructs/listings/lambda_func_1_cleaned.ll: -------------------------------------------------------------------------------- 1 | ; ModuleID = 'lambda_func_1_cleaned.ll' 2 | source_filename = "lambda_func_1_cleaned.ll" 3 | target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" 4 | target triple = "x86_64-unknown-linux-gnu" 5 | 6 | %lambda_args = type { i32, i32, i32 } 7 | 8 | declare i32 @integer_parse() 9 | 10 | define i32 @lambda(%lambda_args* %args, i32 %x) { 11 | %1 = getelementptr %lambda_args, %lambda_args* %args, i32 0, i32 0 12 | %a = load i32, i32* %1 13 | %2 = getelementptr %lambda_args, %lambda_args* %args, i32 0, i32 1 14 | %b = load i32, i32* %2 15 | %3 = getelementptr %lambda_args, %lambda_args* %args, i32 0, i32 2 16 | %c = load i32, i32* %3 17 | %4 = add i32 %a, %b 18 | %5 = sub i32 %4, %c 19 | %6 = mul i32 %5, %x 20 | ret i32 %6 21 | } 22 | 23 | define i32 @foo(i32 %a, i32 %b) { 24 | %args = alloca %lambda_args 25 | %1 = getelementptr %lambda_args, %lambda_args* %args, i32 0, i32 0 26 | store i32 %a, i32* %1 27 | %2 = getelementptr %lambda_args, %lambda_args* %args, i32 0, i32 1 28 | store i32 %b, i32* %2 29 | %c = call i32 @integer_parse() 30 | %3 = getelementptr %lambda_args, %lambda_args* %args, i32 0, i32 2 31 | store i32 %c, i32* %3 32 | %4 = call i32 @lambda(%lambda_args* %args, i32 10) 33 | ret i32 %4 34 | } 35 | -------------------------------------------------------------------------------- /advanced-constructs/listings/listing_4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | generator int foo() 4 | { 5 | yield 1; 6 | yield 2; 7 | yield 3; 8 | } 9 | 10 | int main() 11 | { 12 | foreach (int i in foo()) 13 | printf("Value: %d\n", i); 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /advanced-constructs/listings/listing_5.ll: -------------------------------------------------------------------------------- 1 | %foo_context = type { 2 | i8*, ; 0: block (state) 3 | i32 ; 1: value (result) 4 | } 5 | 6 | define void @foo_setup(%foo_context* %context) nounwind { 7 | ; set up 'block' 8 | %1 = getelementptr %foo_context, %foo_context* %context, i32 0, i32 0 9 | store i8* blockaddress(@foo_yield, %.yield1), i8** %1 10 | 11 | ret void 12 | } 13 | 14 | ; The boolean returned indicates if a result was available or not. 15 | ; Once no more results are available, the caller is expected to not call 16 | ; the iterator again. 17 | define i1 @foo_yield(%foo_context* %context) nounwind { 18 | ; dispatch to the active generator block 19 | %1 = getelementptr %foo_context, %foo_context* %context, i32 0, i32 0 20 | %2 = load i8*, i8** %1 21 | indirectbr i8* %2, [ label %.yield1, label %.yield2, label %.yield3, label %.done ] 22 | 23 | .yield1: 24 | ; store the result value (1) 25 | %3 = getelementptr %foo_context, %foo_context* %context, i32 0, i32 1 26 | store i32 1, i32* %3 27 | 28 | ; make 'block' point to next block to execute 29 | %4 = getelementptr %foo_context, %foo_context* %context, i32 0, i32 0 30 | store i8* blockaddress(@foo_yield, %.yield2), i8** %4 31 | 32 | ret i1 1 33 | 34 | .yield2: 35 | ; store the result value (2) 36 | %5 = getelementptr %foo_context, %foo_context* %context, i32 0, i32 1 37 | store i32 2, i32* %5 38 | 39 | ; make 'block' point to next block to execute 40 | %6 = getelementptr %foo_context, %foo_context* %context, i32 0, i32 0 41 | store i8* blockaddress(@foo_yield, %.yield3), i8** %6 42 | 43 | ret i1 1 44 | 45 | .yield3: 46 | ; store the result value (3) 47 | %7 = getelementptr %foo_context, %foo_context* %context, i32 0, i32 1 48 | store i32 3, i32* %7 49 | 50 | ; make 'block' point to next block to execute 51 | %8 = getelementptr %foo_context, %foo_context* %context, i32 0, i32 0 52 | store i8* blockaddress(@foo_yield, %.done), i8** %8 53 | 54 | ret i1 1 55 | 56 | .done: 57 | ret i1 0 58 | } 59 | 60 | declare i32 @printf(i8*, ...) nounwind 61 | 62 | @.string = internal constant [11 x i8] c"Value: %d\0A\00" 63 | 64 | define void @main() nounwind { 65 | ; allocate and initialize generator context structure 66 | %context = alloca %foo_context 67 | call void @foo_setup(%foo_context* %context) 68 | br label %.head 69 | 70 | .head: 71 | ; foreach (int i in foo()) 72 | %1 = call i1 @foo_yield(%foo_context* %context) 73 | br i1 %1, label %.body, label %.tail 74 | 75 | .body: 76 | %2 = getelementptr %foo_context, %foo_context* %context, i32 0, i32 1 77 | %3 = load i32, i32* %2 78 | %4 = call i32 (i8*, ...) @printf(i8* getelementptr([11 x i8], [11 x i8]* @.string, i32 0, i32 0), i32 %3) 79 | br label %.head 80 | 81 | .tail: 82 | ret void 83 | } 84 | -------------------------------------------------------------------------------- /advanced-constructs/listings/listing_6.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | generator int foo(int start, int after) 4 | { 5 | for (int index = start; index < after; index++) 6 | { 7 | if (index % 2 == 0) 8 | yield index + 1; 9 | else 10 | yield index - 1; 11 | } 12 | } 13 | 14 | int main(void) 15 | { 16 | foreach (int i in foo(0, 5)) 17 | printf("Value: %d\n", i); 18 | 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /advanced-constructs/listings/listing_7.ll: -------------------------------------------------------------------------------- 1 | %foo_context = type { 2 | i8*, ; 0: block (state) 3 | i32, ; 1: start (argument) 4 | i32, ; 2: after (argument) 5 | i32, ; 3: index (local) 6 | i32 ; 4: value (result) 7 | } 8 | 9 | define void @foo_setup(%foo_context* %context, i32 %start, i32 %after) nounwind { 10 | ; set up 'block' 11 | %1 = getelementptr %foo_context, %foo_context* %context, i32 0, i32 0 12 | store i8* blockaddress(@foo_yield, %.init), i8** %1 13 | 14 | ; set up 'start' 15 | %2 = getelementptr %foo_context, %foo_context* %context, i32 0, i32 1 16 | store i32 %start, i32* %2 17 | 18 | ; set up 'after' 19 | %3 = getelementptr %foo_context, %foo_context* %context, i32 0, i32 2 20 | store i32 %after, i32* %3 21 | 22 | ret void 23 | } 24 | 25 | define i1 @foo_yield(%foo_context* %context) nounwind { 26 | ; dispatch to the active generator block 27 | %1 = getelementptr %foo_context, %foo_context* %context, i32 0, i32 0 28 | %2 = load i8*, i8** %1 29 | indirectbr i8* %2, [ label %.init, label %.loop_close, label %.end ] 30 | 31 | .init: 32 | ; copy argument 'start' to the local variable 'index' 33 | %3 = getelementptr %foo_context, %foo_context* %context, i32 0, i32 1 34 | %start = load i32, i32* %3 35 | %4 = getelementptr %foo_context, %foo_context* %context, i32 0, i32 3 36 | store i32 %start, i32* %4 37 | br label %.head 38 | 39 | .head: 40 | ; for (; index < after; ) 41 | %5 = getelementptr %foo_context, %foo_context* %context, i32 0, i32 3 42 | %index = load i32, i32* %5 43 | %6 = getelementptr %foo_context, %foo_context* %context, i32 0, i32 2 44 | %after = load i32, i32* %6 45 | %again = icmp slt i32 %index, %after 46 | br i1 %again, label %.loop_begin, label %.exit 47 | 48 | .loop_begin: 49 | %7 = srem i32 %index, 2 50 | %8 = icmp eq i32 %7, 0 51 | br i1 %8, label %.even, label %.odd 52 | 53 | .even: 54 | ; store 'index + 1' in 'value' 55 | %9 = add i32 %index, 1 56 | %10 = getelementptr %foo_context, %foo_context* %context, i32 0, i32 4 57 | store i32 %9, i32* %10 58 | 59 | ; make 'block' point to the end of the loop (after the yield) 60 | %11 = getelementptr %foo_context, %foo_context* %context, i32 0, i32 0 61 | store i8* blockaddress(@foo_yield, %.loop_close), i8** %11 62 | 63 | ret i1 1 64 | 65 | .odd: 66 | ; store 'index - 1' in value 67 | %12 = sub i32 %index, 1 68 | %13 = getelementptr %foo_context, %foo_context* %context, i32 0, i32 4 69 | store i32 %12, i32* %13 70 | 71 | ; make 'block' point to the end of the loop (after the yield) 72 | %14 = getelementptr %foo_context, %foo_context* %context, i32 0, i32 0 73 | store i8* blockaddress(@foo_yield, %.loop_close), i8** %14 74 | 75 | ret i1 1 76 | 77 | .loop_close: 78 | ; increment 'index' 79 | %15 = getelementptr %foo_context, %foo_context* %context, i32 0, i32 3 80 | %16 = load i32, i32* %15 81 | %17 = add i32 %16, 1 82 | store i32 %17, i32* %15 83 | br label %.head 84 | 85 | .exit: 86 | ; make 'block' point to the %.end label 87 | %x = getelementptr %foo_context, %foo_context* %context, i32 0, i32 0 88 | store i8* blockaddress(@foo_yield, %.end), i8** %x 89 | br label %.end 90 | 91 | .end: 92 | ret i1 0 93 | } 94 | 95 | declare i32 @printf(i8*, ...) nounwind 96 | 97 | @.string = internal constant [11 x i8] c"Value: %d\0A\00" 98 | 99 | define i32 @main() nounwind { 100 | ; allocate and initialize generator context structure 101 | %context = alloca %foo_context 102 | call void @foo_setup(%foo_context* %context, i32 0, i32 5) 103 | br label %.head 104 | 105 | .head: 106 | ; foreach (int i in foo(0, 5)) 107 | %1 = call i1 @foo_yield(%foo_context* %context) 108 | br i1 %1, label %.body, label %.tail 109 | 110 | .body: 111 | %2 = getelementptr %foo_context, %foo_context* %context, i32 0, i32 4 112 | %3 = load i32, i32* %2 113 | %4 = call i32 (i8*, ...) @printf(i8* getelementptr([11 x i8], [11 x i8]* @.string, i32 0, i32 0), i32 %3) 114 | br label %.head 115 | 116 | .tail: 117 | ret i32 0 118 | } 119 | -------------------------------------------------------------------------------- /appendix-a-how-to-implement-a-string-type-in-llvm/index.rst: -------------------------------------------------------------------------------- 1 | How to Implement a String Type in LLVM 2 | ====================================== 3 | 4 | There are two ways to implement a string type in LLVM: 5 | 6 | - To write the implementation in LLVM IR. 7 | - To write the implementation in a higher-level language that generates 8 | IR. 9 | 10 | I'd personally much prefer to use the second method, but for the sake of 11 | the example, I'll go ahead and illustrate a simple but useful string 12 | type in LLVM IR. It assumes a 32-bit architecture, so please replace all 13 | occurrences of ``i32`` with ``i64`` if you are targetting a 64-bit 14 | architecture. 15 | 16 | We'll be making a dynamic, mutable string type that can be appended to 17 | and could also be inserted into, converted to lower case, and so on, 18 | depending on which support functions are defined to operate on the 19 | string type. 20 | 21 | It all boils down to making a suitable type definition for the class and 22 | then define a rich set of functions to operate on the type definition: 23 | 24 | .. code-block:: llvm 25 | 26 | ; The actual type definition for our 'String' type. 27 | %String = type { 28 | i8*, ; 0: buffer; pointer to the character buffer 29 | i32, ; 1: length; the number of chars in the buffer 30 | i32, ; 2: maxlen; the maximum number of chars in the buffer 31 | i32 ; 3: factor; the number of chars to preallocate when growing 32 | } 33 | 34 | define fastcc void @String_Create_Default(%String* %this) nounwind { 35 | ; Initialize 'buffer'. 36 | %1 = getelementptr %String* %this, i32 0, i32 0 37 | store i8* null, i8** %1 38 | 39 | ; Initialize 'length'. 40 | %2 = getelementptr %String* %this, i32 0, i32 1 41 | store i32 0, i32* %2 42 | 43 | ; Initialize 'maxlen'. 44 | %3 = getelementptr %String* %this, i32 0, i32 2 45 | store i32 0, i32* %3 46 | 47 | ; Initialize 'factor'. 48 | %4 = getelementptr %String* %this, i32 0, i32 3 49 | store i32 16, i32* %4 50 | 51 | ret void 52 | } 53 | 54 | declare i8* @malloc(i32) 55 | declare void @free(i8*) 56 | declare i8* @memcpy(i8*, i8*, i32) 57 | 58 | define fastcc void @String_Delete(%String* %this) nounwind { 59 | ; Check if we need to call 'free'. 60 | %1 = getelementptr %String* %this, i32 0, i32 0 61 | %2 = load i8** %1 62 | %3 = icmp ne i8* %2, null 63 | br i1 %3, label %free_begin, label %free_close 64 | 65 | free_begin: 66 | call void @free(i8* %2) 67 | br label %free_close 68 | 69 | free_close: 70 | ret void 71 | } 72 | 73 | define fastcc void @String_Resize(%String* %this, i32 %value) { 74 | ; %output = malloc(%value) 75 | %output = call i8* @malloc(i32 %value) 76 | 77 | ; todo: check return value 78 | 79 | ; %buffer = this->buffer 80 | %1 = getelementptr %String* %this, i32 0, i32 0 81 | %buffer = load i8** %1 82 | 83 | ; %length = this->length 84 | %2 = getelementptr %String* %this, i32 0, i32 1 85 | %length = load i32* %2 86 | 87 | ; memcpy(%output, %buffer, %length) 88 | %3 = call i8* @memcpy(i8* %output, i8* %buffer, i32 %length) 89 | 90 | ; free(%buffer) 91 | call void @free(i8* %buffer) 92 | 93 | ; this->buffer = %output 94 | store i8* %output, i8** %1 95 | 96 | ;this->maxlen = %value (value that was passed into @malloc is the new maxlen) 97 | %4 = getelementptr %String* this, i32 0, i32 2 98 | store i32 %value, i32* %4 99 | ret void 100 | } 101 | 102 | define fastcc void @String_Add_Char(%String* %this, i8 %value) { 103 | ; Check if we need to grow the string. 104 | %1 = getelementptr %String* %this, i32 0, i32 1 105 | %length = load i32* %1 106 | %2 = getelementptr %String* %this, i32 0, i32 2 107 | %maxlen = load i32* %2 108 | ; if length == maxlen: 109 | %3 = icmp eq i32 %length, %maxlen 110 | br i1 %3, label %grow_begin, label %grow_close 111 | 112 | grow_begin: 113 | %4 = getelementptr %String* %this, i32 0, i32 3 114 | %factor = load i32* %4 115 | %5 = add i32 %maxlen, %factor 116 | call void @String_Resize(%String* %this, i32 %5) 117 | br label %grow_close 118 | 119 | grow_close: 120 | %6 = getelementptr %String* %this, i32 0, i32 0 121 | %buffer = load i8** %6 122 | %7 = getelementptr i8* %buffer, i32 %length 123 | store i8 %value, i8* %7 124 | %8 = add i32 %length, 1 125 | store i32 %8, i32* %1 126 | 127 | ret void 128 | } 129 | -------------------------------------------------------------------------------- /appendix-a-how-to-implement-a-string-type-in-llvm/listings/listing_0.ll: -------------------------------------------------------------------------------- 1 | ; The actual type definition for our 'String' type. 2 | %String = type { 3 | i8*, ; 0: buffer; pointer to the character buffer 4 | i32, ; 1: length; the number of chars in the buffer 5 | i32, ; 2: maxlen; the maximum number of chars in the buffer 6 | i32 ; 3: factor; the number of chars to preallocate when growing 7 | } 8 | 9 | define fastcc void @String_Create_Default(%String* %this) nounwind { 10 | ; Initialize 'buffer'. 11 | %1 = getelementptr %String* %this, i32 0, i32 0 12 | store i8* null, i8** %1 13 | 14 | ; Initialize 'length'. 15 | %2 = getelementptr %String* %this, i32 0, i32 1 16 | store i32 0, i32* %2 17 | 18 | ; Initialize 'maxlen'. 19 | %3 = getelementptr %String* %this, i32 0, i32 2 20 | store i32 0, i32* %3 21 | 22 | ; Initialize 'factor'. 23 | %4 = getelementptr %String* %this, i32 0, i32 3 24 | store i32 16, i32* %4 25 | 26 | ret void 27 | } 28 | 29 | declare i8* @malloc(i32) 30 | declare void @free(i8*) 31 | declare i8* @memcpy(i8*, i8*, i32) 32 | 33 | define fastcc void @String_Delete(%String* %this) nounwind { 34 | ; Check if we need to call 'free'. 35 | %1 = getelementptr %String* %this, i32 0, i32 0 36 | %2 = load i8** %1 37 | %3 = icmp ne i8* %2, null 38 | br i1 %3, label %free_begin, label %free_close 39 | 40 | free_begin: 41 | call void @free(i8* %2) 42 | br label %free_close 43 | 44 | free_close: 45 | ret void 46 | } 47 | 48 | define fastcc void @String_Resize(%String* %this, i32 %value) { 49 | ; %output = malloc(%value) 50 | %output = call i8* @malloc(i32 %value) 51 | 52 | ; todo: check return value 53 | 54 | ; %buffer = this->buffer 55 | %1 = getelementptr %String* %this, i32 0, i32 0 56 | %buffer = load i8** %1 57 | 58 | ; %length = this->length 59 | %2 = getelementptr %String* %this, i32 0, i32 1 60 | %length = load i32* %2 61 | 62 | ; memcpy(%output, %buffer, %length) 63 | %3 = call i8* @memcpy(i8* %output, i8* %buffer, i32 %length) 64 | 65 | ; free(%buffer) 66 | call void @free(i8* %buffer) 67 | 68 | ; this->buffer = %output 69 | store i8* %output, i8** %1 70 | 71 | ret void 72 | } 73 | 74 | define fastcc void @String_Add_Char(%String* %this, i8 %value) { 75 | ; Check if we need to grow the string. 76 | %1 = getelementptr %String* %this, i32 0, i32 1 77 | %length = load i32* %1 78 | %2 = getelementptr %String* %this, i32 0, i32 2 79 | %maxlen = load i32* %2 80 | ; if length == maxlen: 81 | %3 = icmp eq i32 %length, %maxlen 82 | br i1 %3, label %grow_begin, label %grow_close 83 | 84 | grow_begin: 85 | %4 = getelementptr %String* %this, i32 0, i32 3 86 | %factor = load i32* %4 87 | %5 = add i32 %maxlen, %factor 88 | call void @String_Resize(%String* %this, i32 %5) 89 | br label %grow_close 90 | 91 | grow_close: 92 | %6 = getelementptr %String* %this, i32 0, i32 0 93 | %buffer = load i8** %6 94 | %7 = getelementptr i8* %buffer, i32 %length 95 | store i8 %value, i8* %7 96 | %8 = add i32 %length, 1 97 | store i32 %8, i32* %1 98 | 99 | ret void 100 | } 101 | -------------------------------------------------------------------------------- /basic-constructs/casts.rst: -------------------------------------------------------------------------------- 1 | Casts 2 | ----- 3 | 4 | There are nine different types of casts: 5 | 6 | - Bitwise casts (type casts). 7 | - Zero-extending casts (unsigned upcasts). 8 | - Sign-extending casts (signed upcasts). 9 | - Truncating casts (signed and unsigned downcasts). 10 | - Floating-point extending casts (float upcasts). 11 | - Floating-point truncating casts (float downcasts). 12 | - Pointer-to-integer casts. 13 | - Integer-to-pointer casts. 14 | - Address-space casts (pointer casts). 15 | 16 | Bitwise Casts 17 | ~~~~~~~~~~~~~ 18 | 19 | A bitwise cast (``bitcast``) reinterprets a given bit pattern without 20 | changing any bits in the operand. For instance, you could make a bitcast 21 | of a pointer to byte into a pointer to some structure as follows: 22 | 23 | .. code-block:: cpp 24 | 25 | typedef struct 26 | { 27 | int a; 28 | } Foo; 29 | 30 | extern void *malloc(size_t size); 31 | extern void free(void *value); 32 | 33 | void allocate() 34 | { 35 | Foo *foo = (Foo *) malloc(sizeof(Foo)); 36 | foo.a = 12; 37 | free(foo); 38 | } 39 | 40 | Becomes: 41 | 42 | .. code-block:: llvm 43 | 44 | %Foo = type { i32 } 45 | 46 | declare i8* @malloc(i32) 47 | declare void @free(i8*) 48 | 49 | define void @allocate() nounwind { 50 | %1 = call i8* @malloc(i32 4) 51 | %foo = bitcast i8* %1 to %Foo* 52 | %2 = getelementptr %Foo, %Foo* %foo, i32 0, i32 0 53 | store i32 12, i32* %2 54 | call void @free(i8* %1) 55 | ret void 56 | } 57 | 58 | Zero-Extending Casts (Unsigned Upcasts) 59 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 60 | 61 | To upcast an unsigned value like in the example below: 62 | 63 | .. code-block:: cpp 64 | 65 | uint8 byte = 117; 66 | uint32 word; 67 | 68 | void main() 69 | { 70 | /* The compiler automatically upcasts the byte to a word. */ 71 | word = byte; 72 | } 73 | 74 | You use the ``zext`` instruction: 75 | 76 | .. code-block:: llvm 77 | 78 | @byte = global i8 117 79 | @word = global i32 0 80 | 81 | define void @main() nounwind { 82 | %1 = load i8, i8* @byte 83 | %2 = zext i8 %1 to i32 84 | store i32 %2, i32* @word 85 | ret void 86 | } 87 | 88 | Sign-Extending Casts (Signed Upcasts) 89 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 90 | 91 | To upcast a signed value, you replace the ``zext`` instruction with the 92 | ``sext`` instruction and everything else works just like in the previous 93 | section: 94 | 95 | .. code-block:: llvm 96 | 97 | @char = global i8 -17 98 | @int = global i32 0 99 | 100 | define void @main() nounwind { 101 | %1 = load i8, i8* @char 102 | %2 = sext i8 %1 to i32 103 | store i32 %2, i32* @int 104 | ret void 105 | } 106 | 107 | Truncating Casts (Signed and Unsigned Downcasts) 108 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 109 | 110 | Both signed and unsigned integers use the same instruction, ``trunc``, 111 | to reduce the size of the number in question. This is because LLVM IR 112 | assumes that all signed integer values are in two's complement format 113 | for which reason ``trunc`` is sufficient to handle both cases: 114 | 115 | .. code-block:: llvm 116 | 117 | @int = global i32 -1 118 | @char = global i8 0 119 | 120 | define void @main() nounwind { 121 | %1 = load i32, i32* @int 122 | %2 = trunc i32 %1 to i8 123 | store i8 %2, i8* @char 124 | ret void 125 | } 126 | 127 | Floating-Point Extending Casts (Float Upcasts) 128 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 129 | 130 | Floating points numbers can be extended using the ``fpext`` instruction: 131 | 132 | .. code-block:: cpp 133 | 134 | float small = 1.25; 135 | double large; 136 | 137 | void main() 138 | { 139 | /* The compiler inserts an implicit float upcast. */ 140 | large = small; 141 | } 142 | 143 | Becomes: 144 | 145 | .. code-block:: llvm 146 | 147 | @small = global float 1.25 148 | @large = global double 0.0 149 | 150 | define void @main() nounwind { 151 | %1 = load float, float* @small 152 | %2 = fpext float %1 to double 153 | store double %2, double* @large 154 | ret void 155 | } 156 | 157 | Floating-Point Truncating Casts (Float Downcasts) 158 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 159 | 160 | Likewise, a floating point number can be truncated to a smaller size: 161 | 162 | .. code-block:: llvm 163 | 164 | @large = global double 1.25 165 | @small = global float 0.0 166 | 167 | define void @main() nounwind { 168 | %1 = load double, double* @large 169 | %2 = fptrunc double %1 to float 170 | store float %2, float* @small 171 | ret void 172 | } 173 | 174 | Pointer-to-Integer Casts 175 | ~~~~~~~~~~~~~~~~~~~~~~~~ 176 | 177 | Pointers do not support arithmetic, which is sometimes needed when doing 178 | systems programming. LLVM has support for casting pointer types to 179 | integer types using the ``ptrtoint`` instruction 180 | (`reference `__) 181 | 182 | Integer-to-Pointer Casts 183 | ~~~~~~~~~~~~~~~~~~~~~~~~ 184 | 185 | The ``inttoptr`` instruction is used to cast an integer back to a 186 | pointer 187 | (`reference `__). 188 | 189 | Address-Space Casts (Pointer Casts) 190 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 191 | -------------------------------------------------------------------------------- /basic-constructs/constants.rst: -------------------------------------------------------------------------------- 1 | Constants 2 | ========= 3 | 4 | There are two different kinds of constants: 5 | 6 | - Constants that do *not* occupy allocated memory. 7 | - Constants that *do* occupy allocated memory. 8 | 9 | The former are always expanded inline by the compiler as there is no 10 | LLVM IR equivalent of those. In other words, the compiler simply inserts 11 | the constant value wherever it is being used in a computation: 12 | 13 | .. code-block:: llvm 14 | 15 | %1 = add i32 %0, 17 ; 17 is an inlined constant 16 | 17 | Constants that do occupy memory are defined using the ``constant`` 18 | keyword: 19 | 20 | .. code-block:: llvm 21 | 22 | @hello = internal constant [6 x i8] c"hello\00" 23 | %struct = type { i32, i8 } 24 | @struct_constant = internal constant %struct { i32 16, i8 4 } 25 | 26 | Such a constant is really a global variable whose visibility can be limited 27 | with ``private`` or ``internal`` so that it is invisible outside the current 28 | module. 29 | 30 | Constant Expressions 31 | -------------------- 32 | 33 | An example for constant expressions are ``sizeof``-style computations. 34 | Even though the compiler ought to know the exact size of everything in 35 | use (for statically checked languages), it can at times be convenient to 36 | ask LLVM to figure out the size of a structure for you. This is done 37 | with the following little snippet of code: 38 | 39 | .. code-block:: llvm 40 | 41 | %Struct = type { i8, i32, i8* } 42 | @Struct_size = constant i32 ptrtoint (%Struct* getelementptr (%Struct, %Struct* null, i32 1) to i32) 43 | 44 | ``@Struct_size`` will now contain the size of the structure ``%Struct``. 45 | The trick is to compute the offset of the second element 46 | 47 | in the zero-based array starting at ``null`` and that way get the size 48 | of the structure. 49 | -------------------------------------------------------------------------------- /basic-constructs/functions.rst: -------------------------------------------------------------------------------- 1 | Function Definitions and Declarations 2 | ===================================== 3 | 4 | The translation of function definitions depends on a range of factors, 5 | ranging from the calling convention in use, whether the function is 6 | exception-aware or not, and if the function is to be publicly available 7 | outside the module. 8 | 9 | Simple Public Functions 10 | ----------------------- 11 | 12 | The most basic model is: 13 | 14 | .. code-block:: cpp 15 | 16 | int Bar(void) 17 | { 18 | return 17; 19 | } 20 | 21 | Becomes: 22 | 23 | .. code-block:: llvm 24 | 25 | define i32 @Bar() nounwind { 26 | ret i32 17 27 | } 28 | 29 | 30 | Simple Private Functions 31 | ------------------------ 32 | 33 | A static function is a function private to a module that cannot be 34 | referenced from outside of the defining module: 35 | 36 | .. code-block:: llvm 37 | 38 | define private i32 @Foo() nounwind { 39 | ret i32 17 40 | } 41 | 42 | Note that this does not directly map to public/private in the context of 43 | ``C++``. Two ``C++`` classes inside one LLVM module can call each other 44 | private methods, because they're simply module-level private functions for 45 | LLVM. 46 | 47 | 48 | Function Prototypes 49 | ------------------- 50 | 51 | A function prototype, aka a profile, is translated into an equivalent 52 | ``declare`` declaration in LLVM IR: 53 | 54 | .. code-block:: cpp 55 | 56 | int Bar(int value); 57 | 58 | Becomes: 59 | 60 | .. code-block:: llvm 61 | 62 | declare i32 @Bar(i32 %value) 63 | 64 | Or you can leave out the descriptive parameter name: 65 | 66 | .. code-block:: llvm 67 | 68 | declare i32 @Bar(i32) 69 | 70 | Functions with a Variable Number of Parameters 71 | ---------------------------------------------- 72 | 73 | To call a so-called vararg function, you first need to define or declare 74 | it using the elipsis (...) and then you need to make use of a special 75 | syntax for function calls that allows you to explicitly list the types of 76 | the parameters of the function that is being called. This "hack" exists 77 | to allow overriding a call to a function such as a function with 78 | variable parameters. Please notice that you only need to specify the 79 | return type once, not twice as you'd have to do if it was a true cast: 80 | 81 | .. code-block:: llvm 82 | 83 | declare i32 @printf(i8*, ...) nounwind 84 | 85 | @.textstr = internal constant [20 x i8] c"Argument count: %d\0A\00" 86 | 87 | define i32 @main(i32 %argc, i8** %argv) nounwind { 88 | ; printf("Argument count: %d\n", argc) 89 | %1 = call i32 (i8*, ...) @printf(i8* getelementptr([20 x i8], [20 x i8]* @.textstr, i32 0, i32 0), i32 %argc) 90 | ret i32 0 91 | } 92 | 93 | Function Overloading 94 | -------------------- 95 | 96 | Function overloading is actually not dealt with on the level of LLVM IR, 97 | but on the source language. Function names are mangled, so that they 98 | encode the types they take as parameter and return in their function 99 | name. For a C++ example: 100 | 101 | .. code-block:: cpp 102 | 103 | int function(int a, int b) { 104 | return a + b; 105 | } 106 | 107 | double function(double a, double b, double x) { 108 | return a*b + x; 109 | } 110 | 111 | For LLVM these two are completely different functions, with different 112 | names etc. 113 | 114 | .. code-block:: llvm 115 | 116 | define i32 @_Z8functionii(i32 %a, i32 %b) #0 { 117 | ; [...] 118 | ret i32 %5 119 | } 120 | 121 | define double @_Z8functionddd(double %a, double %b, double %x) #0 { 122 | ; [...] 123 | ret double %8 124 | } 125 | 126 | Struct by Value as Parameter or Return Value 127 | -------------------------------------------- 128 | 129 | Classes or structs are often passed around by value, implicitly cloning 130 | the objects when they are passed. But they are not 131 | 132 | .. code-block:: cpp 133 | 134 | struct Point { 135 | double x; 136 | double y; 137 | double z; 138 | }; 139 | 140 | Point add_points(Point a, Point b) { 141 | Point p; 142 | p.x = a.x + b.x; 143 | p.y = a.y + b.y; 144 | p.z = a.z + b.z; 145 | return p; 146 | } 147 | 148 | This simple example is in turn compiled to 149 | 150 | .. code-block:: llvm 151 | 152 | %struct.Point = type { double, double, double } 153 | 154 | define void @add_points(%struct.Point* noalias sret %agg.result, 155 | %struct.Point* byval align 8 %a, 156 | %struct.Point* byval align 8 %b) #0 { 157 | ; there is no alloca here for Point p; 158 | ; p.x = a.x + b.x; 159 | %1 = getelementptr inbounds %struct.Point, %struct.Point* %a, i32 0, i32 0 160 | %2 = load double, double* %1, align 8 161 | %3 = getelementptr inbounds %struct.Point, %struct.Point* %b, i32 0, i32 0 162 | %4 = load double, double* %3, align 8 163 | %5 = fadd double %2, %4 164 | %6 = getelementptr inbounds %struct.Point, %struct.Point* %agg.result, i32 0, i32 0 165 | store double %5, double* %6, align 8 166 | ; p.y = a.y + b.y; 167 | %7 = getelementptr inbounds %struct.Point, %struct.Point* %a, i32 0, i32 1 168 | %8 = load double, double* %7, align 8 169 | %9 = getelementptr inbounds %struct.Point, %struct.Point* %b, i32 0, i32 1 170 | %10 = load double, double* %9, align 8 171 | %11 = fadd double %8, %10 172 | %12 = getelementptr inbounds %struct.Point, %struct.Point* %agg.result, i32 0, i32 1 173 | store double %11, double* %12, align 8 174 | ; p.z = a.z + b.z; 175 | %13 = getelementptr inbounds %struct.Point, %struct.Point* %a, i32 0, i32 2 176 | %14 = load double, double* %13, align 8 177 | %15 = getelementptr inbounds %struct.Point, %struct.Point* %b, i32 0, i32 2 178 | %16 = load double, double* %15, align 8 179 | %17 = fadd double %14, %16 180 | %18 = getelementptr inbounds %struct.Point, %struct.Point* %agg.result, i32 0, i32 2 181 | store double %17, double* %18, align 8 182 | ; there is no real returned value, because the previous stores directly wrote 183 | ; to the caller allocated value via %agg.result 184 | ret void 185 | } 186 | 187 | We can see that the function now actually returns ``void`` and another 188 | parameter was added. The first parameter is a pointer to the result, 189 | which is allocated by the caller. The pointer has the attribute 190 | ``noalias`` because there is no way that one of the parameters might 191 | point to the same location. The ``sret`` attribute indicates that this 192 | is the return value. 193 | 194 | The parameters have the ``byval`` attribute, which indicates that they 195 | are structs that are passed by value. 196 | 197 | Let's see how this function would be called. 198 | 199 | .. code-block:: cpp 200 | 201 | int main() { 202 | Point a = {1.0, 3.0, 4.0}; 203 | Point b = {2.0, 8.0, 5.0}; 204 | Point c = add_points(a, b); 205 | return 0; 206 | } 207 | 208 | is compiled to: 209 | 210 | .. code-block:: llvm 211 | 212 | define i32 @main() #1 { 213 | ; these are the a, b, c in the scope of main 214 | %a = alloca %struct.Point, align 8 215 | %b = alloca %struct.Point, align 8 216 | %c = alloca %struct.Point, align 8 217 | ; these are copies, which are passed as arguments 218 | %1 = alloca %struct.Point, align 8 219 | %2 = alloca %struct.Point, align 8 220 | ; copy the global initializer main::a to %a 221 | %3 = bitcast %struct.Point* %a to i8* 222 | call void @llvm.memcpy.p0i8.p0i8.i64(i8* %3, i8* bitcast (%struct.Point* @main.a to i8*), i64 24, i32 8, i1 false) 223 | ; copy the global initializer main::b to %b 224 | %4 = bitcast %struct.Point* %b to i8* 225 | call void @llvm.memcpy.p0i8.p0i8.i64(i8* %4, i8* bitcast (%struct.Point* @main.b to i8*), i64 24, i32 8, i1 false) 226 | ; clone a to %1 227 | %5 = bitcast %struct.Point* %1 to i8* 228 | %6 = bitcast %struct.Point* %a to i8* 229 | call void @llvm.memcpy.p0i8.p0i8.i64(i8* %5, i8* %6, i64 24, i32 8, i1 false) 230 | ; clone b to %2 231 | %7 = bitcast %struct.Point* %2 to i8* 232 | %8 = bitcast %struct.Point* %b to i8* 233 | call void @llvm.memcpy.p0i8.p0i8.i64(i8* %7, i8* %8, i64 24, i32 8, i1 false) 234 | ; call add_points with the cloned values 235 | call void @add_points(%struct.Point* sret %c, %struct.Point* byval align 8 %1, %struct.Point* byval align 8 %2) 236 | ; [...] 237 | } 238 | 239 | We can see that the caller, in our case ``main``, allocates space for 240 | the return value ``%c`` and also makes sure to clone the parameters 241 | ``a`` and ``b`` before actually passing them by reference. 242 | 243 | Exception-Aware Functions 244 | ------------------------- 245 | 246 | A function that is aware of being part of a larger scheme of 247 | exception-handling is called an exception-aware function. Depending upon 248 | the type of exception handling being employed, the function may either 249 | return a pointer to an exception instance, create a 250 | ``setjmp``/``longjmp`` frame, or simply specify the ``uwtable`` (for 251 | UnWind Table) attribute. These cases will all be covered in great detail 252 | in the chapter on *Exception Handling* below. 253 | 254 | Function Pointers 255 | ----------------- 256 | 257 | Function pointers are expressed almost like in C and C++: 258 | 259 | .. code-block:: cpp 260 | 261 | int (*Function)(char *buffer); 262 | 263 | Becomes: 264 | 265 | .. code-block:: llvm 266 | 267 | @Function = global i32(i8*)* null 268 | -------------------------------------------------------------------------------- /basic-constructs/global-variables.rst: -------------------------------------------------------------------------------- 1 | Global Variables 2 | ---------------- 3 | 4 | Global variables are trivial to implement in LLVM IR: 5 | 6 | .. code-block:: cpp 7 | 8 | int variable = 21; 9 | 10 | int main() 11 | { 12 | variable = variable * 2; 13 | return variable; 14 | } 15 | 16 | Becomes: 17 | 18 | .. code-block:: llvm 19 | 20 | @variable = global i32 21 21 | 22 | define i32 @main() { 23 | %1 = load i32, ptr @variable ; load the global variable 24 | %2 = mul i32 %1, 2 25 | store i32 %2, ptr @variable ; store instruction to write to global variable 26 | ret i32 %2 27 | } 28 | 29 | 30 | 31 | 32 | Globals are prefixed with the ``@`` character. You can see that also 33 | functions, such as ``main``, are also global variables in LLVM. 34 | Please notice that LLVM views global variables as pointers; so you must 35 | explicitly dereference the global variable using the ``load`` instruction 36 | when accessing its value, likewise you must explicitly store the value of 37 | a global variable using the ``store`` instruction. In that regard LLVM IR 38 | is closer to Assembly than C. 39 | -------------------------------------------------------------------------------- /basic-constructs/index.rst: -------------------------------------------------------------------------------- 1 | **************** 2 | Basic Constructs 3 | **************** 4 | 5 | In this chapter, we'll look at the most basic and simple constructs that 6 | are part of nearly all imperative/OOP languages out there. 7 | 8 | .. toctree:: 9 | :maxdepth: 2 10 | :caption: Contents: 11 | :glob: 12 | 13 | global-variables 14 | local-variables 15 | constants 16 | structures 17 | casts 18 | functions 19 | unions 20 | -------------------------------------------------------------------------------- /basic-constructs/listings/.gitignore: -------------------------------------------------------------------------------- 1 | rust_enum 2 | a.out 3 | -------------------------------------------------------------------------------- /basic-constructs/listings/Makefile: -------------------------------------------------------------------------------- 1 | include ../../common.mk 2 | -------------------------------------------------------------------------------- /basic-constructs/listings/cpp_variant.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std::literals; 5 | 6 | int main() 7 | { 8 | std::variant x, y, z; 9 | x = 42; 10 | y = 1337.0; 11 | z = true; 12 | 13 | if (std::holds_alternative(x)) { 14 | std::cout << "A boolean! " << std::get(x) << std::endl; 15 | } 16 | if (std::holds_alternative(y)) { 17 | std::cout << "A boolean! " << std::get(y) << std::endl; 18 | } 19 | if (std::holds_alternative(z)) { 20 | std::cout << "A boolean! " << std::get(z) << std::endl; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /basic-constructs/listings/function_overloading.cpp: -------------------------------------------------------------------------------- 1 | int func(int a, int b) { 2 | return a + b; 3 | } 4 | 5 | double func(double a, double b, double x) { 6 | return a*b + x; 7 | } 8 | -------------------------------------------------------------------------------- /basic-constructs/listings/listing_0.cpp: -------------------------------------------------------------------------------- 1 | int variable = 14; 2 | 3 | int main() 4 | { 5 | return variable; 6 | } 7 | -------------------------------------------------------------------------------- /basic-constructs/listings/listing_1.ll: -------------------------------------------------------------------------------- 1 | @variable = global i32 14 2 | 3 | define i32 @main() nounwind { 4 | %1 = load i32* @variable 5 | ret i32 %1 6 | } 7 | -------------------------------------------------------------------------------- /basic-constructs/listings/listing_10.cpp: -------------------------------------------------------------------------------- 1 | int Bar(void) 2 | { 3 | return 17; 4 | } 5 | -------------------------------------------------------------------------------- /basic-constructs/listings/listing_11.ll: -------------------------------------------------------------------------------- 1 | define i32 @Bar() nounwind { 2 | ret i32 17 3 | } 4 | -------------------------------------------------------------------------------- /basic-constructs/listings/listing_12.ll: -------------------------------------------------------------------------------- 1 | define private i32 @Foo() nounwind { 2 | ret i32 17 3 | } 4 | -------------------------------------------------------------------------------- /basic-constructs/listings/listing_13.ll: -------------------------------------------------------------------------------- 1 | declare i32 @printf(i8*, ...) nounwind 2 | 3 | @.text = internal constant [20 x i8] c"Argument count: %d\0A\00" 4 | 5 | define i32 @main(i32 %argc, i8** %argv) nounwind { 6 | ; printf("Argument count: %d\n", argc) 7 | %1 = call i32 (i8*, ...)* @printf(i8* getelementptr([20 x i8]* @.text, i32 0, i32 0), i32 %argc) 8 | ret i32 0 9 | } 10 | -------------------------------------------------------------------------------- /basic-constructs/listings/listing_14.cpp: -------------------------------------------------------------------------------- 1 | int (*Function)(char *buffer); 2 | -------------------------------------------------------------------------------- /basic-constructs/listings/listing_15.ll: -------------------------------------------------------------------------------- 1 | @Function = global i32(i8*)* null 2 | -------------------------------------------------------------------------------- /basic-constructs/listings/listing_16.cpp: -------------------------------------------------------------------------------- 1 | typedef struct 2 | { 3 | int a; 4 | } Foo; 5 | 6 | extern void *malloc(size_t size); 7 | extern void free(void *value); 8 | 9 | void allocate() 10 | { 11 | Foo *foo = (Foo *) malloc(sizeof(Foo)); 12 | foo.a = 12; 13 | free(foo); 14 | } 15 | -------------------------------------------------------------------------------- /basic-constructs/listings/listing_17.ll: -------------------------------------------------------------------------------- 1 | %Foo = type { i32 } 2 | 3 | declare i8* @malloc(i32) 4 | declare void @free(i8*) 5 | 6 | define void @allocate() nounwind { 7 | %1 = call i8* @malloc(i32 4) 8 | %foo = bitcast i8* %1 to %Foo* 9 | %2 = getelementptr %Foo* %foo, i32 0, i32 0 10 | store i32 12, i32* %2 11 | call void @free(i8* %1) 12 | ret void 13 | } 14 | -------------------------------------------------------------------------------- /basic-constructs/listings/listing_18.cpp: -------------------------------------------------------------------------------- 1 | uint8 byte = 117; 2 | uint32 word; 3 | 4 | void main() 5 | { 6 | /* The compiler automatically upcasts the byte to a word. */ 7 | word = byte; 8 | } 9 | -------------------------------------------------------------------------------- /basic-constructs/listings/listing_19.ll: -------------------------------------------------------------------------------- 1 | @byte = global i8 117 2 | @word = global i32 0 3 | 4 | define void @main() nounwind { 5 | %1 = load i8* @byte 6 | %2 = zext i8 %1 to i32 7 | store i32 %2, i32* @word 8 | ret void 9 | } 10 | -------------------------------------------------------------------------------- /basic-constructs/listings/listing_2.ll: -------------------------------------------------------------------------------- 1 | %1 = some computation 2 | -------------------------------------------------------------------------------- /basic-constructs/listings/listing_20.ll: -------------------------------------------------------------------------------- 1 | @char = global i8 -17 2 | @int = global i32 0 3 | 4 | define void @main() nounwind { 5 | %1 = load i8* @char 6 | %2 = sext i8 %1 to i32 7 | store i32 %2, i32* @int 8 | ret void 9 | } 10 | -------------------------------------------------------------------------------- /basic-constructs/listings/listing_21.ll: -------------------------------------------------------------------------------- 1 | @int = global i32 -1 2 | @char = global i8 0 3 | 4 | define void @main() nounwind { 5 | %1 = load i32* @int 6 | %2 = trunc i32 %1 to i8 7 | store i8 %2, i8* @char 8 | ret void 9 | } 10 | -------------------------------------------------------------------------------- /basic-constructs/listings/listing_22.cpp: -------------------------------------------------------------------------------- 1 | float small = 1.25; 2 | double large; 3 | 4 | void main() 5 | { 6 | /* The compiler inserts an implicit float upcast. */ 7 | large = small; 8 | } 9 | -------------------------------------------------------------------------------- /basic-constructs/listings/listing_23.ll: -------------------------------------------------------------------------------- 1 | @small = global float 1.25 2 | @large = global double 0.0 3 | 4 | define void @main() nounwind { 5 | %1 = load float* @small 6 | %2 = fpext float %1 to double 7 | store double %2, double* @large 8 | ret void 9 | } 10 | -------------------------------------------------------------------------------- /basic-constructs/listings/listing_24.ll: -------------------------------------------------------------------------------- 1 | @large = global double 1.25 2 | @small = global float 0.0 3 | 4 | define void @main() nounwind { 5 | %1 = load double* @large 6 | %2 = fptrunc double %1 to float 7 | store float %2, float* @small 8 | ret void 9 | } 10 | -------------------------------------------------------------------------------- /basic-constructs/listings/listing_25.cpp: -------------------------------------------------------------------------------- 1 | void Bar(struct Foo *); 2 | -------------------------------------------------------------------------------- /basic-constructs/listings/listing_26.ll: -------------------------------------------------------------------------------- 1 | %Foo = type opaque 2 | declare void @Bar(%Foo) 3 | -------------------------------------------------------------------------------- /basic-constructs/listings/listing_27.cpp: -------------------------------------------------------------------------------- 1 | struct Foo 2 | { 3 | size_t _length; 4 | }; 5 | -------------------------------------------------------------------------------- /basic-constructs/listings/listing_28.ll: -------------------------------------------------------------------------------- 1 | %Foo = type { i32 } 2 | -------------------------------------------------------------------------------- /basic-constructs/listings/listing_29.ll: -------------------------------------------------------------------------------- 1 | %Object = type { 2 | %Object*, ; 0: above; the parent pointer 3 | i32 ; 1: value; the value of the node 4 | } 5 | -------------------------------------------------------------------------------- /basic-constructs/listings/listing_3.ll: -------------------------------------------------------------------------------- 1 | %2 = alloca i32 2 | -------------------------------------------------------------------------------- /basic-constructs/listings/listing_30.cpp: -------------------------------------------------------------------------------- 1 | union Foo 2 | { 3 | int a; 4 | char *b; 5 | double c; 6 | }; 7 | Foo Union; 8 | -------------------------------------------------------------------------------- /basic-constructs/listings/listing_31.ll: -------------------------------------------------------------------------------- 1 | %union.Foo = type { double } 2 | @Union = %union.Foo { 0.0 } 3 | -------------------------------------------------------------------------------- /basic-constructs/listings/listing_32.ll: -------------------------------------------------------------------------------- 1 | %1 = bitcast %union.Foo* @Union to i32* 2 | store i32 1, i32* %1 3 | %2 = bitcast %union.Foo* @Union to i8** 4 | store i8* null, i8** %2 5 | -------------------------------------------------------------------------------- /basic-constructs/listings/listing_4.ll: -------------------------------------------------------------------------------- 1 | %1 = add i32 %0, 17 ; 17 is an inlined constant 2 | -------------------------------------------------------------------------------- /basic-constructs/listings/listing_5.ll: -------------------------------------------------------------------------------- 1 | @hello = internal constant [6 x i8] c"hello\00" 2 | %struct = type { i32, i8 } 3 | @struct_constant = internal constant %struct { i32 16, i8 4 } 4 | -------------------------------------------------------------------------------- /basic-constructs/listings/listing_6.ll: -------------------------------------------------------------------------------- 1 | %Struct = type { i8, i32, i8* } 2 | @Struct_size = constant i32 ptrtoint (%Struct* getelementptr (%Struct* null, i32 1)) to i32 3 | -------------------------------------------------------------------------------- /basic-constructs/listings/listing_7.cpp: -------------------------------------------------------------------------------- 1 | int Bar(int value); 2 | -------------------------------------------------------------------------------- /basic-constructs/listings/listing_8.ll: -------------------------------------------------------------------------------- 1 | declare i32 @Bar(i32 %value) 2 | -------------------------------------------------------------------------------- /basic-constructs/listings/listing_9.ll: -------------------------------------------------------------------------------- 1 | declare i32 @Bar(i32) 2 | -------------------------------------------------------------------------------- /basic-constructs/listings/rust_enum.ll: -------------------------------------------------------------------------------- 1 | ; ModuleID = 'rust_enum.cgu-0.rs' 2 | source_filename = "rust_enum.cgu-0.rs" 3 | target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" 4 | target triple = "x86_64-unknown-linux-gnu" 5 | 6 | %str_slice = type { i8*, i64 } 7 | %"core::fmt::ArgumentV1" = type { %"core::fmt::Void"*, [0 x i8], i8 (%"core::fmt::Void"*, %"core::fmt::Formatter"*)*, [0 x i8] } 8 | %"core::fmt::Void" = type { {}, [0 x i8] } 9 | %"core::fmt::Formatter" = type { %"core::option::Option", [0 x i8], %"core::option::Option", [0 x i8], { i8*, void (i8*)** }, [0 x i8], %"core::slice::Iter", [0 x i8], { %"core::fmt::ArgumentV1"*, i64 }, [0 x i8], i32, [0 x i8], i32, [0 x i8], i8, [7 x i8] } 10 | %"core::option::Option" = type { i64, [0 x i64], [1 x i64] } 11 | %"core::slice::Iter" = type { %"core::fmt::ArgumentV1"*, [0 x i8], %"core::fmt::ArgumentV1"*, [0 x i8], %"core::marker::PhantomData<&core::fmt::ArgumentV1>", [0 x i8] } 12 | %"core::marker::PhantomData<&core::fmt::ArgumentV1>" = type {} 13 | %"core::fmt::Arguments" = type { { %str_slice*, i64 }, [0 x i8], %"core::option::Option<&[core::fmt::rt::v1::Argument]>", [0 x i8], { %"core::fmt::ArgumentV1"*, i64 }, [0 x i8] } 14 | %"core::option::Option<&[core::fmt::rt::v1::Argument]>" = type { { %"core::fmt::rt::v1::Argument"*, i64 }, [0 x i8] } 15 | %"core::fmt::rt::v1::Argument" = type { %"core::fmt::rt::v1::Position", [0 x i8], %"core::fmt::rt::v1::FormatSpec", [0 x i8] } 16 | %"core::fmt::rt::v1::Position" = type { i64, [0 x i64], [1 x i64] } 17 | %"core::fmt::rt::v1::FormatSpec" = type { %"core::fmt::rt::v1::Count", [0 x i8], %"core::fmt::rt::v1::Count", [0 x i8], i32, [0 x i8], i32, [0 x i8], i8, [7 x i8] } 18 | %"core::fmt::rt::v1::Count" = type { i64, [0 x i64], [1 x i64] } 19 | %Foo = type { i8, [7 x i8], [1 x i64] } 20 | 21 | @_ZN9rust_enum4main15__STATIC_FMTSTR17h593e97caa92fe17aE = internal constant { %str_slice*, i64 } { %str_slice* getelementptr inbounds ([2 x %str_slice], [2 x %str_slice]* @ref.2, i32 0, i32 0), i64 2 }, align 8 22 | @_ZN9rust_enum4main15__STATIC_FMTSTR17h55b6efdcfd70c0fbE = internal constant { %str_slice*, i64 } { %str_slice* getelementptr inbounds ([2 x %str_slice], [2 x %str_slice]* @ref.2, i32 0, i32 0), i64 2 }, align 8 23 | @_ZN9rust_enum4main15__STATIC_FMTSTR17hbde30b16cc9bb817E = internal constant { %str_slice*, i64 } { %str_slice* getelementptr inbounds ([2 x %str_slice], [2 x %str_slice]* @ref.2, i32 0, i32 0), i64 2 }, align 8 24 | @str.0 = internal constant [11 x i8] c"A boolean! " 25 | @str.1 = internal constant [1 x i8] c"\0A" 26 | @ref.2 = internal unnamed_addr constant [2 x %str_slice] [%str_slice { i8* getelementptr inbounds ([11 x i8], [11 x i8]* @str.0, i32 0, i32 0), i64 11 }, %str_slice { i8* getelementptr inbounds ([1 x i8], [1 x i8]* @str.1, i32 0, i32 0), i64 1 }], align 8 27 | 28 | ; core::fmt::ArgumentV1::new 29 | ; Function Attrs: uwtable 30 | define internal void @_ZN4core3fmt10ArgumentV13new17h177fce648e2d33b4E(%"core::fmt::ArgumentV1"* noalias nocapture sret dereferenceable(16), i8* noalias readonly dereferenceable(1), i8 (i8*, %"core::fmt::Formatter"*)*) unnamed_addr #0 { 31 | start: 32 | %transmute_temp1 = alloca %"core::fmt::Void"* 33 | %transmute_temp = alloca i8 (%"core::fmt::Void"*, %"core::fmt::Formatter"*)* 34 | %3 = bitcast i8 (%"core::fmt::Void"*, %"core::fmt::Formatter"*)** %transmute_temp to i8 (i8*, %"core::fmt::Formatter"*)** 35 | store i8 (i8*, %"core::fmt::Formatter"*)* %2, i8 (i8*, %"core::fmt::Formatter"*)** %3, align 8 36 | %4 = load i8 (%"core::fmt::Void"*, %"core::fmt::Formatter"*)*, i8 (%"core::fmt::Void"*, %"core::fmt::Formatter"*)** %transmute_temp, !nonnull !1 37 | br label %bb1 38 | 39 | bb1: ; preds = %start 40 | %5 = bitcast %"core::fmt::Void"** %transmute_temp1 to i8** 41 | store i8* %1, i8** %5, align 8 42 | %6 = load %"core::fmt::Void"*, %"core::fmt::Void"** %transmute_temp1, !nonnull !1 43 | br label %bb2 44 | 45 | bb2: ; preds = %bb1 46 | %7 = getelementptr inbounds %"core::fmt::ArgumentV1", %"core::fmt::ArgumentV1"* %0, i32 0, i32 0 47 | store %"core::fmt::Void"* %6, %"core::fmt::Void"** %7 48 | %8 = getelementptr inbounds %"core::fmt::ArgumentV1", %"core::fmt::ArgumentV1"* %0, i32 0, i32 2 49 | store i8 (%"core::fmt::Void"*, %"core::fmt::Formatter"*)* %4, i8 (%"core::fmt::Void"*, %"core::fmt::Formatter"*)** %8 50 | ret void 51 | } 52 | 53 | ; core::fmt::Arguments::new_v1 54 | ; Function Attrs: inlinehint uwtable 55 | define internal void @_ZN4core3fmt9Arguments6new_v117hb35981d82b379493E(%"core::fmt::Arguments"* noalias nocapture sret dereferenceable(48), %str_slice* noalias nonnull readonly, i64, %"core::fmt::ArgumentV1"* noalias nonnull readonly, i64) unnamed_addr #1 { 56 | start: 57 | %_6 = alloca %"core::option::Option<&[core::fmt::rt::v1::Argument]>" 58 | %5 = getelementptr inbounds %"core::option::Option<&[core::fmt::rt::v1::Argument]>", %"core::option::Option<&[core::fmt::rt::v1::Argument]>"* %_6, i32 0, i32 0, i32 0 59 | store %"core::fmt::rt::v1::Argument"* null, %"core::fmt::rt::v1::Argument"** %5 60 | %6 = getelementptr inbounds %"core::fmt::Arguments", %"core::fmt::Arguments"* %0, i32 0, i32 0 61 | %7 = getelementptr inbounds { %str_slice*, i64 }, { %str_slice*, i64 }* %6, i32 0, i32 0 62 | store %str_slice* %1, %str_slice** %7 63 | %8 = getelementptr inbounds { %str_slice*, i64 }, { %str_slice*, i64 }* %6, i32 0, i32 1 64 | store i64 %2, i64* %8 65 | %9 = getelementptr inbounds %"core::fmt::Arguments", %"core::fmt::Arguments"* %0, i32 0, i32 2 66 | %10 = bitcast %"core::option::Option<&[core::fmt::rt::v1::Argument]>"* %_6 to i8* 67 | %11 = bitcast %"core::option::Option<&[core::fmt::rt::v1::Argument]>"* %9 to i8* 68 | call void @llvm.memcpy.p0i8.p0i8.i64(i8* %11, i8* %10, i64 16, i32 8, i1 false) 69 | %12 = getelementptr inbounds %"core::fmt::Arguments", %"core::fmt::Arguments"* %0, i32 0, i32 4 70 | %13 = getelementptr inbounds { %"core::fmt::ArgumentV1"*, i64 }, { %"core::fmt::ArgumentV1"*, i64 }* %12, i32 0, i32 0 71 | store %"core::fmt::ArgumentV1"* %3, %"core::fmt::ArgumentV1"** %13 72 | %14 = getelementptr inbounds { %"core::fmt::ArgumentV1"*, i64 }, { %"core::fmt::ArgumentV1"*, i64 }* %12, i32 0, i32 1 73 | store i64 %4, i64* %14 74 | ret void 75 | } 76 | 77 | ; rust_enum::main 78 | ; Function Attrs: uwtable 79 | define internal void @_ZN9rust_enum4main17hbfbce8e9dfa39c4cE() unnamed_addr #0 { 80 | start: 81 | %tmp_ret5 = alloca %"core::fmt::ArgumentV1" 82 | %tmp_ret4 = alloca %"core::fmt::ArgumentV1" 83 | %tmp_ret = alloca %"core::fmt::ArgumentV1" 84 | %_42 = alloca { i8*, [0 x i8] } 85 | %_41 = alloca [1 x %"core::fmt::ArgumentV1"] 86 | %_36 = alloca %"core::fmt::Arguments" 87 | %x3 = alloca i8 88 | %_28 = alloca { i8*, [0 x i8] } 89 | %_27 = alloca [1 x %"core::fmt::ArgumentV1"] 90 | %_22 = alloca %"core::fmt::Arguments" 91 | %x2 = alloca i8 92 | %_19 = alloca {} 93 | %_13 = alloca { i8*, [0 x i8] } 94 | %_12 = alloca [1 x %"core::fmt::ArgumentV1"] 95 | %_7 = alloca %"core::fmt::Arguments" 96 | %x1 = alloca i8 97 | %_4 = alloca {} 98 | %z = alloca %Foo 99 | %y = alloca %Foo 100 | %x = alloca %Foo 101 | %_0 = alloca {} 102 | %0 = getelementptr inbounds %Foo, %Foo* %x, i32 0, i32 0 103 | store i8 1, i8* %0 104 | %1 = bitcast %Foo* %x to { i8, [3 x i8], i32, [0 x i8] }* 105 | %2 = getelementptr inbounds { i8, [3 x i8], i32, [0 x i8] }, { i8, [3 x i8], i32, [0 x i8] }* %1, i32 0, i32 2 106 | store i32 42, i32* %2 107 | %3 = getelementptr inbounds %Foo, %Foo* %y, i32 0, i32 0 108 | store i8 2, i8* %3 109 | %4 = bitcast %Foo* %y to { i8, [7 x i8], double, [0 x i8] }* 110 | %5 = getelementptr inbounds { i8, [7 x i8], double, [0 x i8] }, { i8, [7 x i8], double, [0 x i8] }* %4, i32 0, i32 2 111 | store double 1.337000e+03, double* %5 112 | %6 = getelementptr inbounds %Foo, %Foo* %z, i32 0, i32 0 113 | store i8 0, i8* %6 114 | %7 = bitcast %Foo* %z to { i8, [0 x i8], i8, [0 x i8] }* 115 | %8 = getelementptr inbounds { i8, [0 x i8], i8, [0 x i8] }, { i8, [0 x i8], i8, [0 x i8] }* %7, i32 0, i32 2 116 | store i8 1, i8* %8 117 | %9 = getelementptr inbounds %Foo, %Foo* %x, i32 0, i32 0 118 | %10 = load i8, i8* %9, !range !2 119 | %11 = zext i8 %10 to i64 120 | switch i64 %11, label %bb1 [ 121 | i64 0, label %bb2 122 | ] 123 | 124 | bb1: ; preds = %start 125 | br label %bb3 126 | 127 | bb2: ; preds = %start 128 | %12 = bitcast %Foo* %x to { i8, [0 x i8], i8, [0 x i8] }* 129 | %13 = getelementptr inbounds { i8, [0 x i8], i8, [0 x i8] }, { i8, [0 x i8], i8, [0 x i8] }* %12, i32 0, i32 2 130 | %14 = load i8, i8* %13, !range !3 131 | %15 = trunc i8 %14 to i1 132 | %16 = zext i1 %15 to i8 133 | store i8 %16, i8* %x1 134 | %17 = load %str_slice*, %str_slice** getelementptr inbounds ({ %str_slice*, i64 }, { %str_slice*, i64 }* @_ZN9rust_enum4main15__STATIC_FMTSTR17h593e97caa92fe17aE, i32 0, i32 0), !nonnull !1 135 | %18 = load i64, i64* getelementptr inbounds ({ %str_slice*, i64 }, { %str_slice*, i64 }* @_ZN9rust_enum4main15__STATIC_FMTSTR17h593e97caa92fe17aE, i32 0, i32 1) 136 | %19 = getelementptr inbounds { i8*, [0 x i8] }, { i8*, [0 x i8] }* %_13, i32 0, i32 0 137 | store i8* %x1, i8** %19 138 | %20 = getelementptr inbounds { i8*, [0 x i8] }, { i8*, [0 x i8] }* %_13, i32 0, i32 0 139 | %21 = load i8*, i8** %20, !nonnull !1 140 | ; call core::fmt::ArgumentV1::new 141 | call void @_ZN4core3fmt10ArgumentV13new17h177fce648e2d33b4E(%"core::fmt::ArgumentV1"* noalias nocapture sret dereferenceable(16) %tmp_ret, i8* noalias readonly dereferenceable(1) %21, i8 (i8*, %"core::fmt::Formatter"*)* @"_ZN43_$LT$bool$u20$as$u20$core..fmt..Display$GT$3fmt17h404028510cff9d6fE") 142 | %22 = getelementptr inbounds %"core::fmt::ArgumentV1", %"core::fmt::ArgumentV1"* %tmp_ret, i32 0, i32 0 143 | %23 = getelementptr inbounds %"core::fmt::ArgumentV1", %"core::fmt::ArgumentV1"* %tmp_ret, i32 0, i32 2 144 | %24 = load %"core::fmt::Void"*, %"core::fmt::Void"** %22, !nonnull !1 145 | %25 = load i8 (%"core::fmt::Void"*, %"core::fmt::Formatter"*)*, i8 (%"core::fmt::Void"*, %"core::fmt::Formatter"*)** %23, !nonnull !1 146 | br label %bb4 147 | 148 | bb3: ; preds = %bb6, %bb1 149 | %26 = getelementptr inbounds %Foo, %Foo* %y, i32 0, i32 0 150 | %27 = load i8, i8* %26, !range !2 151 | %28 = zext i8 %27 to i64 152 | switch i64 %28, label %bb7 [ 153 | i64 0, label %bb8 154 | ] 155 | 156 | bb4: ; preds = %bb2 157 | %29 = getelementptr inbounds [1 x %"core::fmt::ArgumentV1"], [1 x %"core::fmt::ArgumentV1"]* %_12, i32 0, i32 0 158 | %30 = getelementptr inbounds %"core::fmt::ArgumentV1", %"core::fmt::ArgumentV1"* %29, i32 0, i32 0 159 | store %"core::fmt::Void"* %24, %"core::fmt::Void"** %30 160 | %31 = getelementptr inbounds %"core::fmt::ArgumentV1", %"core::fmt::ArgumentV1"* %29, i32 0, i32 2 161 | store i8 (%"core::fmt::Void"*, %"core::fmt::Formatter"*)* %25, i8 (%"core::fmt::Void"*, %"core::fmt::Formatter"*)** %31 162 | %32 = bitcast [1 x %"core::fmt::ArgumentV1"]* %_12 to %"core::fmt::ArgumentV1"* 163 | ; call core::fmt::Arguments::new_v1 164 | call void @_ZN4core3fmt9Arguments6new_v117hb35981d82b379493E(%"core::fmt::Arguments"* noalias nocapture sret dereferenceable(48) %_7, %str_slice* noalias nonnull readonly %17, i64 %18, %"core::fmt::ArgumentV1"* noalias nonnull readonly %32, i64 1) 165 | br label %bb5 166 | 167 | bb5: ; preds = %bb4 168 | ; call std::io::stdio::_print 169 | call void @_ZN3std2io5stdio6_print17h7ce09810ca5a75e5E(%"core::fmt::Arguments"* noalias nocapture dereferenceable(48) %_7) 170 | br label %bb6 171 | 172 | bb6: ; preds = %bb5 173 | br label %bb3 174 | 175 | bb7: ; preds = %bb3 176 | br label %bb9 177 | 178 | bb8: ; preds = %bb3 179 | %33 = bitcast %Foo* %y to { i8, [0 x i8], i8, [0 x i8] }* 180 | %34 = getelementptr inbounds { i8, [0 x i8], i8, [0 x i8] }, { i8, [0 x i8], i8, [0 x i8] }* %33, i32 0, i32 2 181 | %35 = load i8, i8* %34, !range !3 182 | %36 = trunc i8 %35 to i1 183 | %37 = zext i1 %36 to i8 184 | store i8 %37, i8* %x2 185 | %38 = load %str_slice*, %str_slice** getelementptr inbounds ({ %str_slice*, i64 }, { %str_slice*, i64 }* @_ZN9rust_enum4main15__STATIC_FMTSTR17h55b6efdcfd70c0fbE, i32 0, i32 0), !nonnull !1 186 | %39 = load i64, i64* getelementptr inbounds ({ %str_slice*, i64 }, { %str_slice*, i64 }* @_ZN9rust_enum4main15__STATIC_FMTSTR17h55b6efdcfd70c0fbE, i32 0, i32 1) 187 | %40 = getelementptr inbounds { i8*, [0 x i8] }, { i8*, [0 x i8] }* %_28, i32 0, i32 0 188 | store i8* %x2, i8** %40 189 | %41 = getelementptr inbounds { i8*, [0 x i8] }, { i8*, [0 x i8] }* %_28, i32 0, i32 0 190 | %42 = load i8*, i8** %41, !nonnull !1 191 | ; call core::fmt::ArgumentV1::new 192 | call void @_ZN4core3fmt10ArgumentV13new17h177fce648e2d33b4E(%"core::fmt::ArgumentV1"* noalias nocapture sret dereferenceable(16) %tmp_ret4, i8* noalias readonly dereferenceable(1) %42, i8 (i8*, %"core::fmt::Formatter"*)* @"_ZN43_$LT$bool$u20$as$u20$core..fmt..Display$GT$3fmt17h404028510cff9d6fE") 193 | %43 = getelementptr inbounds %"core::fmt::ArgumentV1", %"core::fmt::ArgumentV1"* %tmp_ret4, i32 0, i32 0 194 | %44 = getelementptr inbounds %"core::fmt::ArgumentV1", %"core::fmt::ArgumentV1"* %tmp_ret4, i32 0, i32 2 195 | %45 = load %"core::fmt::Void"*, %"core::fmt::Void"** %43, !nonnull !1 196 | %46 = load i8 (%"core::fmt::Void"*, %"core::fmt::Formatter"*)*, i8 (%"core::fmt::Void"*, %"core::fmt::Formatter"*)** %44, !nonnull !1 197 | br label %bb10 198 | 199 | bb9: ; preds = %bb12, %bb7 200 | %47 = getelementptr inbounds %Foo, %Foo* %z, i32 0, i32 0 201 | %48 = load i8, i8* %47, !range !2 202 | %49 = zext i8 %48 to i64 203 | switch i64 %49, label %bb13 [ 204 | i64 0, label %bb14 205 | ] 206 | 207 | bb10: ; preds = %bb8 208 | %50 = getelementptr inbounds [1 x %"core::fmt::ArgumentV1"], [1 x %"core::fmt::ArgumentV1"]* %_27, i32 0, i32 0 209 | %51 = getelementptr inbounds %"core::fmt::ArgumentV1", %"core::fmt::ArgumentV1"* %50, i32 0, i32 0 210 | store %"core::fmt::Void"* %45, %"core::fmt::Void"** %51 211 | %52 = getelementptr inbounds %"core::fmt::ArgumentV1", %"core::fmt::ArgumentV1"* %50, i32 0, i32 2 212 | store i8 (%"core::fmt::Void"*, %"core::fmt::Formatter"*)* %46, i8 (%"core::fmt::Void"*, %"core::fmt::Formatter"*)** %52 213 | %53 = bitcast [1 x %"core::fmt::ArgumentV1"]* %_27 to %"core::fmt::ArgumentV1"* 214 | ; call core::fmt::Arguments::new_v1 215 | call void @_ZN4core3fmt9Arguments6new_v117hb35981d82b379493E(%"core::fmt::Arguments"* noalias nocapture sret dereferenceable(48) %_22, %str_slice* noalias nonnull readonly %38, i64 %39, %"core::fmt::ArgumentV1"* noalias nonnull readonly %53, i64 1) 216 | br label %bb11 217 | 218 | bb11: ; preds = %bb10 219 | ; call std::io::stdio::_print 220 | call void @_ZN3std2io5stdio6_print17h7ce09810ca5a75e5E(%"core::fmt::Arguments"* noalias nocapture dereferenceable(48) %_22) 221 | br label %bb12 222 | 223 | bb12: ; preds = %bb11 224 | br label %bb9 225 | 226 | bb13: ; preds = %bb9 227 | br label %bb15 228 | 229 | bb14: ; preds = %bb9 230 | %54 = bitcast %Foo* %z to { i8, [0 x i8], i8, [0 x i8] }* 231 | %55 = getelementptr inbounds { i8, [0 x i8], i8, [0 x i8] }, { i8, [0 x i8], i8, [0 x i8] }* %54, i32 0, i32 2 232 | %56 = load i8, i8* %55, !range !3 233 | %57 = trunc i8 %56 to i1 234 | %58 = zext i1 %57 to i8 235 | store i8 %58, i8* %x3 236 | %59 = load %str_slice*, %str_slice** getelementptr inbounds ({ %str_slice*, i64 }, { %str_slice*, i64 }* @_ZN9rust_enum4main15__STATIC_FMTSTR17hbde30b16cc9bb817E, i32 0, i32 0), !nonnull !1 237 | %60 = load i64, i64* getelementptr inbounds ({ %str_slice*, i64 }, { %str_slice*, i64 }* @_ZN9rust_enum4main15__STATIC_FMTSTR17hbde30b16cc9bb817E, i32 0, i32 1) 238 | %61 = getelementptr inbounds { i8*, [0 x i8] }, { i8*, [0 x i8] }* %_42, i32 0, i32 0 239 | store i8* %x3, i8** %61 240 | %62 = getelementptr inbounds { i8*, [0 x i8] }, { i8*, [0 x i8] }* %_42, i32 0, i32 0 241 | %63 = load i8*, i8** %62, !nonnull !1 242 | ; call core::fmt::ArgumentV1::new 243 | call void @_ZN4core3fmt10ArgumentV13new17h177fce648e2d33b4E(%"core::fmt::ArgumentV1"* noalias nocapture sret dereferenceable(16) %tmp_ret5, i8* noalias readonly dereferenceable(1) %63, i8 (i8*, %"core::fmt::Formatter"*)* @"_ZN43_$LT$bool$u20$as$u20$core..fmt..Display$GT$3fmt17h404028510cff9d6fE") 244 | %64 = getelementptr inbounds %"core::fmt::ArgumentV1", %"core::fmt::ArgumentV1"* %tmp_ret5, i32 0, i32 0 245 | %65 = getelementptr inbounds %"core::fmt::ArgumentV1", %"core::fmt::ArgumentV1"* %tmp_ret5, i32 0, i32 2 246 | %66 = load %"core::fmt::Void"*, %"core::fmt::Void"** %64, !nonnull !1 247 | %67 = load i8 (%"core::fmt::Void"*, %"core::fmt::Formatter"*)*, i8 (%"core::fmt::Void"*, %"core::fmt::Formatter"*)** %65, !nonnull !1 248 | br label %bb16 249 | 250 | bb15: ; preds = %bb18, %bb13 251 | ret void 252 | 253 | bb16: ; preds = %bb14 254 | %68 = getelementptr inbounds [1 x %"core::fmt::ArgumentV1"], [1 x %"core::fmt::ArgumentV1"]* %_41, i32 0, i32 0 255 | %69 = getelementptr inbounds %"core::fmt::ArgumentV1", %"core::fmt::ArgumentV1"* %68, i32 0, i32 0 256 | store %"core::fmt::Void"* %66, %"core::fmt::Void"** %69 257 | %70 = getelementptr inbounds %"core::fmt::ArgumentV1", %"core::fmt::ArgumentV1"* %68, i32 0, i32 2 258 | store i8 (%"core::fmt::Void"*, %"core::fmt::Formatter"*)* %67, i8 (%"core::fmt::Void"*, %"core::fmt::Formatter"*)** %70 259 | %71 = bitcast [1 x %"core::fmt::ArgumentV1"]* %_41 to %"core::fmt::ArgumentV1"* 260 | ; call core::fmt::Arguments::new_v1 261 | call void @_ZN4core3fmt9Arguments6new_v117hb35981d82b379493E(%"core::fmt::Arguments"* noalias nocapture sret dereferenceable(48) %_36, %str_slice* noalias nonnull readonly %59, i64 %60, %"core::fmt::ArgumentV1"* noalias nonnull readonly %71, i64 1) 262 | br label %bb17 263 | 264 | bb17: ; preds = %bb16 265 | ; call std::io::stdio::_print 266 | call void @_ZN3std2io5stdio6_print17h7ce09810ca5a75e5E(%"core::fmt::Arguments"* noalias nocapture dereferenceable(48) %_36) 267 | br label %bb18 268 | 269 | bb18: ; preds = %bb17 270 | br label %bb15 271 | } 272 | 273 | ; Function Attrs: argmemonly nounwind 274 | declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i32, i1) #2 275 | 276 | ; ::fmt 277 | declare i8 @"_ZN43_$LT$bool$u20$as$u20$core..fmt..Display$GT$3fmt17h404028510cff9d6fE"(i8* noalias readonly dereferenceable(1), %"core::fmt::Formatter"* dereferenceable(96)) unnamed_addr #3 278 | 279 | ; std::io::stdio::_print 280 | declare void @_ZN3std2io5stdio6_print17h7ce09810ca5a75e5E(%"core::fmt::Arguments"* noalias nocapture dereferenceable(48)) unnamed_addr #3 281 | 282 | define i64 @main(i64, i8**) unnamed_addr { 283 | top: 284 | ; call std::rt::lang_start 285 | %2 = call i64 @_ZN3std2rt10lang_start17h97aba2334c85f570E(void ()* @_ZN9rust_enum4main17hbfbce8e9dfa39c4cE, i64 %0, i8** %1) 286 | ret i64 %2 287 | } 288 | 289 | ; std::rt::lang_start 290 | declare i64 @_ZN3std2rt10lang_start17h97aba2334c85f570E(void ()*, i64, i8**) unnamed_addr #3 291 | 292 | attributes #0 = { uwtable "probe-stack"="__rust_probestack" } 293 | attributes #1 = { inlinehint uwtable "probe-stack"="__rust_probestack" } 294 | attributes #2 = { argmemonly nounwind } 295 | attributes #3 = { "probe-stack"="__rust_probestack" } 296 | 297 | !llvm.module.flags = !{!0} 298 | 299 | !0 = !{i32 1, !"PIE Level", i32 2} 300 | !1 = !{} 301 | !2 = !{i8 0, i8 3} 302 | !3 = !{i8 0, i8 2} 303 | -------------------------------------------------------------------------------- /basic-constructs/listings/rust_enum.rs: -------------------------------------------------------------------------------- 1 | enum Foo { 2 | ABool(bool), 3 | AInteger(i32), 4 | ADouble(f64), 5 | } 6 | 7 | fn main() { 8 | let x = Foo::AInteger(42); 9 | let y = Foo::ADouble(1337.0); 10 | let z = Foo::ABool(true); 11 | 12 | if let Foo::ABool(b) = x { 13 | println!("A boolean! {}", b) 14 | } 15 | if let Foo::ABool(b) = y { 16 | println!("A boolean! {}", b) 17 | } 18 | if let Foo::ABool(b) = z { 19 | println!("A boolean! {}", b) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /basic-constructs/listings/struct_by_val.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct Point { 4 | double x; 5 | double y; 6 | double z; 7 | }; 8 | 9 | 10 | Point make_point() { 11 | Point p; 12 | p.x = 0; 13 | p.y = 0; 14 | p.z = 0; 15 | return p; 16 | } 17 | 18 | 19 | Point add_points(Point a, Point b) { 20 | Point p; 21 | p.x = a.x + b.x; 22 | p.y = a.y + b.y; 23 | p.z = a.z + b.z; 24 | return p; 25 | } 26 | 27 | int main() { 28 | Point a = {1.0, 3.0, 4.0}; 29 | Point b = {2.0, 8.0, 5.0}; 30 | Point c = add_points(a, b); 31 | printf("%f - %f\n", c.x, c.y); 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /basic-constructs/listings/struct_member_access.cpp: -------------------------------------------------------------------------------- 1 | struct Foo 2 | { 3 | int a; 4 | char *b; 5 | double c; 6 | }; 7 | 8 | int main(void) 9 | { 10 | Foo foo; 11 | char **bptr = &foo.b; 12 | 13 | Foo bar[100]; 14 | bar[17].c = 0.0; 15 | 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /basic-constructs/listings/struct_member_access_cleaned.ll: -------------------------------------------------------------------------------- 1 | ; ModuleID = 'struct_member_access.cpp' 2 | source_filename = "struct_member_access.cpp" 3 | target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" 4 | target triple = "x86_64-unknown-linux-gnu" 5 | 6 | %struct.Foo = type { i32, i8*, double } 7 | 8 | ; Function Attrs: noinline norecurse nounwind uwtable 9 | define i32 @main() #0 { 10 | %1 = alloca i32, align 4 11 | %2 = alloca %struct.Foo, align 8 12 | %3 = alloca i8**, align 8 13 | %4 = alloca [100 x %struct.Foo], align 16 14 | store i32 0, i32* %1, align 4 15 | %5 = getelementptr inbounds %struct.Foo, %struct.Foo* %2, i32 0, i32 1 16 | store i8** %5, i8*** %3, align 8 17 | %p = getelementptr [100 x %struct.Foo], [100 x %struct.Foo]* %4, i64 0, i64 17, i32 0, i32 2 18 | store double 0.000000e+00, double* %p, align 8 19 | ret i32 0 20 | } 21 | 22 | attributes #0 = { noinline norecurse nounwind uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } 23 | 24 | !llvm.ident = !{!0} 25 | 26 | !0 = !{!"clang version 4.0.1 (tags/RELEASE_401/final)"} 27 | -------------------------------------------------------------------------------- /basic-constructs/listings/struct_member_access_old.ll: -------------------------------------------------------------------------------- 1 | %Foo = type { 2 | i32, ; 0: a 3 | i8*, ; 1: b 4 | double ; 2: c 5 | } 6 | 7 | define i32 @main() nounwind { 8 | ; Foo foo 9 | %foo = alloca %Foo 10 | ; char **bptr = &foo.b 11 | %1 = getelementptr %Foo* %foo, i32 0, i32 1 12 | 13 | ; Foo bar[100] 14 | %bar = alloca %Foo, i32 100 15 | ; bar[17].c = 0.0 16 | %2 = getelementptr %Foo* %bar, i32 17, i32 2 17 | store double 0.0, double* %2 18 | 19 | ret i32 0 20 | } 21 | -------------------------------------------------------------------------------- /basic-constructs/local-variables.rst: -------------------------------------------------------------------------------- 1 | Local Variables 2 | --------------- 3 | 4 | There are two kinds of local variables in LLVM: 5 | 6 | - Temporary variables/Registers 7 | - Stack-allocated local variables. 8 | 9 | The former is created by introducing a new symbol for the variable: 10 | 11 | .. code-block:: llvm 12 | 13 | %reg = add i32 4, 2 14 | 15 | The latter is created by allocating the variable on the stack: 16 | 17 | .. code-block:: llvm 18 | 19 | %stack = alloca i32 20 | 21 | 22 | Nearly every instruction returns a value, that is usually assigned to a 23 | temporary variable. Because of the SSA form of the LLVM IR, a temporary 24 | variable can only be assigned once. The following code snippet would produce an 25 | error: 26 | 27 | .. code-block:: llvm 28 | 29 | %tmp = add i32 4, 2 30 | %tmp = add i32 4, 1 ; Error here 31 | 32 | To conform to SSA you will often see something like this: 33 | 34 | .. code-block:: llvm 35 | 36 | %tmp.0 = add i32 4, 2 37 | %tmp.1 = add i32 4, 1 ; fine now 38 | 39 | Which can be further shortened to: 40 | 41 | .. code-block:: llvm 42 | 43 | %0 = add i32 4, 2 44 | %1 = add i32 4, 1 45 | 46 | 47 | The number of such local variables is basically unbounded. Because a real 48 | machine does have a rather limited number of registers the compiler backend 49 | might need to put some of these temporaries on the stack. 50 | 51 | Please notice that ``alloca`` yields a pointer to the allocated type. As is 52 | generally the case in LLVM, you must explicitly use a ``load`` or ``store`` 53 | instruction to read or write the value respectively. 54 | 55 | The use of ``alloca`` allows for a neat trick that can simplify your 56 | code generator in some cases. The trick is to explicitly allocate all 57 | mutable variables, including arguments, on the stack, initialize them 58 | with the appropriate initial value and then operate on the stack as if 59 | that was your end goal. The trick is to run the "memory to register 60 | promotion" pass on your code as part of the optimization phase. This 61 | will make LLVM store as many of the stack variables in registers as it 62 | possibly can. That way you don't have to ensure that the generated 63 | program is in SSA form but can generate code without having to worry 64 | about this aspect of the code generation. 65 | 66 | This trick is also described in the chapter on `Mutable Variables in 67 | Kaleidoscope `__, 68 | in the tutorial on the `LLVM website `__. 69 | -------------------------------------------------------------------------------- /basic-constructs/structures.rst: -------------------------------------------------------------------------------- 1 | Structures 2 | ========== 3 | 4 | LLVM IR already includes the concept of structures so there isn't much to do: 5 | 6 | .. code-block:: cpp 7 | 8 | struct Foo 9 | { 10 | size_t x; 11 | double y; 12 | }; 13 | 14 | It is only a matter of discarding the actual field names and then index with 15 | numerals starting from zero: 16 | 17 | .. code-block:: llvm 18 | 19 | %Foo = type { 20 | i64, ; index 0 = x 21 | double ; index 1 = y 22 | } 23 | 24 | 25 | Nested Structures 26 | ----------------- 27 | 28 | Nested structures are also straightforward. They compose in exactly the same 29 | way as a C/C++ ``struct``. 30 | 31 | .. code-block:: cpp 32 | 33 | struct FooBar 34 | { 35 | Foo x; 36 | char* c; 37 | Foo* y; 38 | } 39 | 40 | .. code-block:: llvm 41 | 42 | %FooBar = type { 43 | %Foo, ; index 0 = x 44 | i8*, ; index 1 = c 45 | %Foo* ; index 2 = y 46 | } 47 | 48 | 49 | Incomplete Structure Types 50 | -------------------------- 51 | 52 | Incomplete types are very useful for hiding the details of what fields a 53 | given structure has. A well-designed C interface can be made so that no 54 | details of the structure are revealed to the client, so that the client 55 | cannot inspect or modify private members inside the structure: 56 | 57 | .. code-block:: cpp 58 | 59 | void Bar(struct Foo *); 60 | 61 | Becomes: 62 | 63 | .. code-block:: llvm 64 | 65 | %Foo = type opaque 66 | declare void @Bar(%Foo) 67 | 68 | 69 | 70 | Accessing a Structure Member 71 | ---------------------------- 72 | 73 | As already told, structure members are referenced by index rather than 74 | by name in LLVM IR. And at no point do you need to, or should you, 75 | compute the offset of a given structure member yourself. The 76 | ``getelementptr`` (short GEP) instruction is available to compute a pointer to any 77 | structure member with no overhead (the ``getelementptr`` instruction is 78 | typically coascaled into the actual ``load`` or ``store`` instruction). 79 | The ``getelementptr`` instruction even has it's own article over at the docs 80 | [#llvm-gep-doc]_. You can also find more information in the language reference 81 | manual [#llvm-gep-langref]_. 82 | 83 | So let's assume we have the following C++ struct: 84 | 85 | .. code-block:: cpp 86 | 87 | struct Foo 88 | { 89 | int a; 90 | char *b; 91 | double c; 92 | }; 93 | 94 | This maps pretty straight forward to the following LLVM type. The GEP indices 95 | are in the comments beside the subtypes. 96 | 97 | .. code-block:: llvm 98 | 99 | %Foo = type { 100 | i32, ; 0: a 101 | i8*, ; 1: b 102 | double ; 2: c 103 | } 104 | 105 | 106 | Now we allocate the object on the stack and access the member ``b``, which is 107 | at index 1 and has type ``char*`` in C++. 108 | 109 | .. code-block:: cpp 110 | 111 | Foo foo; 112 | char **bptr = &foo.b; 113 | 114 | First the object is allocated with the ``alloca`` instruction on the stack. To 115 | access the ``b`` member, the GEP instruction is used to compute a pointer to 116 | the memory location. 117 | 118 | .. code-block:: llvm 119 | 120 | %foo = alloca %Foo 121 | ; char **bptr = &foo.b 122 | %1 = getelementptr %Foo, %Foo* %foo, i32 0, i32 1 123 | 124 | 125 | Now let's see what happens if we create an array of ``Foo`` objects. Consider 126 | the following C++ snippet: 127 | 128 | .. code-block:: cpp 129 | 130 | Foo bar[100]; 131 | bar[17].c = 0.0; 132 | 133 | 134 | It will translate to roughly something like the following LLVM IR. First a 135 | pointer to 100 ``Foo`` objects is allocated. Then the GEP instruction is used 136 | to retrieve the second element of the 17th entry in the array. This is done 137 | within one GEP instruction: 138 | 139 | .. code-block:: llvm 140 | 141 | ; Foo bar[100] 142 | %bar = alloca %Foo, i32 100 143 | ; bar[17].c = 0.0 144 | %2 = getelementptr %Foo, %Foo* %bar, i32 17, i32 2 145 | store double 0.0, double* %2 146 | 147 | 148 | Note that newer versions of ``clang`` will produce code that directly uses the 149 | built-in support for Array types [#llvm-array-langref]_. This explicitly 150 | associates the length of an array with the allocated object. GEP instructions 151 | can also have more than two indices to compute addresses deep inside nested 152 | objects. 153 | 154 | .. code-block:: llvm 155 | 156 | %bar = alloca [100 x %Foo] 157 | %p = getelementptr [100 x %Foo], [100 x %Foo]* %bar, i64 0, i64 17, i32 2 158 | store double 0.000000e+00, double* %p, align 8 159 | 160 | 161 | It is highly recommended to read the LLVM docs about the GEP instruction very 162 | thoroughly (see [#llvm-gep-doc]_ [#llvm-gep-langref]_). 163 | 164 | .. [#llvm-gep-doc] `The Often Misunderstood GEP Instruction `_ 165 | .. [#llvm-gep-langref] `LangRef: getelementptr Instruction `_ 166 | .. [#llvm-array-langref] `LangRef: Array type `_ 167 | -------------------------------------------------------------------------------- /basic-constructs/unions.rst: -------------------------------------------------------------------------------- 1 | Unions 2 | ====== 3 | 4 | Unions are getting more and more rare as the years have shown that they 5 | are quite dangerous to use; especially the C variant that does not have 6 | a selector field to indicate which of the union's variants are valid. 7 | Some may still have a legacy reason to use unions. In fact, LLVM does 8 | not support unions at all: 9 | 10 | .. code-block:: cpp 11 | 12 | union Foo 13 | { 14 | int a; 15 | char *b; 16 | double c; 17 | }; 18 | 19 | Foo Union; 20 | 21 | Becomes this when run through clang++: 22 | 23 | .. code-block:: llvm 24 | 25 | %union.Foo = type { double } 26 | @Union = %union.Foo { 0.0 } 27 | 28 | What happened here? Where did the other union members go? The answer is 29 | that in LLVM there are no unions; there are only structs 30 | that can be cast into whichever type the front-end want to cast the 31 | struct into. So to access the above union from LLVM IR, you'd use the 32 | ``bitcast`` instruction to cast a pointer to the "union" into whatever 33 | pointer you'd want it to be: 34 | 35 | .. code-block:: llvm 36 | 37 | %1 = bitcast %union.Foo* @Union to i32* 38 | store i32 1, i32* %1 39 | %2 = bitcast %union.Foo* @Union to i8** 40 | store i8* null, i8** %2 41 | 42 | This may seem strange, but the truth is that a union is nothing more than a 43 | piece of memory that is being accessed using different implicit pointer casts. 44 | There is no type-safety when dealing with unions. 45 | 46 | If you want to support unions in your front-end language, you should 47 | simply allocate the total size of the union (i.e. the size of the 48 | largest member) and then generate code to reinterpret the allocated 49 | memory as needed. 50 | 51 | The cleanest approach might be to simply allocate a range of bytes 52 | (``i8``), possibly with alignment padding at the end, and then cast 53 | whenever you access the structure. That way you'd be sure you did 54 | everything properly all the time. 55 | 56 | 57 | Tagged Unions 58 | ------------- 59 | 60 | When dealing with unions in C, one typically adds another field that signals 61 | the content of the union, since accidently interpreting the bytes of a 62 | ``double`` as a ``char*``, can have disastrous consequences. 63 | 64 | Many modern programming languages feature type-safe tagged unions. Rust has 65 | ``enum`` types, that can optionally contain values. C++ has the ``variant`` 66 | type since C++17. 67 | 68 | Consider the following short rust program, that defines an ``enum`` type that 69 | can hold three different primitive types. 70 | 71 | .. literalinclude:: listings/rust_enum.rs 72 | :language: rust 73 | 74 | ``rustc`` generates something similar to the following LLVM IR to 75 | initialize the ``Foo`` variables. 76 | 77 | .. code-block:: llvm 78 | 79 | ; basic type definition 80 | %Foo = type { i8, [8 x i8] } 81 | ; Variants of Foo 82 | %Foo_ABool = type { i8, i8 } ; tagged with 0 83 | %Foo_AInteger = type { i8, i32 } ; tagged with 1 84 | %Foo_ADouble = type { i8, double } ; tagged with 2 85 | 86 | ; allocate the first Foo 87 | %x = alloca %Foo 88 | ; pointer to the first element of type i8 (the tag) 89 | %0 = getelementptr inbounds %Foo, %Foo* %x, i32 0, i32 0 90 | ; set tag to '1' 91 | store i8 1, i8* %0 92 | ; bitcast Foo to the right Foo variant 93 | %1 = bitcast %Foo* %x to %Foo_AInteger* 94 | ; store the constant '42' 95 | %2 = getelementptr inbounds %Foo_AInteger, %Foo_AInteger* %1, i32 0, i32 1 96 | store i32 42, i32* %2 97 | 98 | ; allocate and initialize the second Foo 99 | %y = alloca %Foo 100 | %3 = getelementptr inbounds %Foo, %Foo* %y, i32 0, i32 0 101 | ; this time the tag is '2' 102 | store i8 2, i8* %3 103 | ; cast to variant and store double constant 104 | %4 = bitcast %Foo* %y to %Foo_ADouble* 105 | %5 = getelementptr inbounds %Foo_ADouble, %Foo_ADouble* %4, i32 0, i32 1 106 | store double 1.337000e+03, double* %5 107 | 108 | 109 | To check whether the given ``Foo`` object is a certain variant, the tag must be 110 | retrieved and compared to the desired value. 111 | 112 | .. code-block:: llvm 113 | 114 | %9 = getelementptr inbounds %Foo, %Foo* %x, i32 0, i32 0 115 | %10 = load i8, i8* %9 116 | ; check if tag is '0', which identifies the variant Foo_ABool 117 | %11 = icmp i8 %10, 0 118 | br i1 %11, label %bb1, label %bb2 119 | 120 | bb1: 121 | ; cast to variant 122 | %12 = bitcast %Foo* %x to %Foo_ABool* 123 | ; retrieve boolean 124 | %13 = getelementptr inbounds %Foo_ABool, %Foo_ABool* %12, i32 0, i32 1 125 | %14 = load i8, i8* %13, 126 | %15 = trunc i8 %14 to i1 127 | ; <...> 128 | -------------------------------------------------------------------------------- /common.mk: -------------------------------------------------------------------------------- 1 | CC=clang 2 | CXX=clang++ 3 | CXXFLAGS=-emit-llvm -std=c++14 -O0 4 | CFLAGS=-emit-llvm -O0 5 | 6 | RUSTC=rustc 7 | RUSTFLAGS= 8 | 9 | %.ll: %.cpp 10 | $(CXX) -S $(CXXFLAGS) $< 11 | 12 | %.ll: %.c 13 | $(CC) -S $(CFLAGS) $< 14 | 15 | %.bc: %.ll 16 | $(CXX) -c $(CXXFLAGS) $< 17 | 18 | %.ll: %.rs 19 | $(RUSTC) --emit-ir=llvm $< 20 | 21 | clean: 22 | -$(RM) *.bc 23 | -------------------------------------------------------------------------------- /conf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # 4 | 5 | # extensions = ['sphinx.ext.todo', 'sphinx.ext.mathjax'] 6 | extensions = [] 7 | 8 | # Add any paths that contain templates here, relative to this directory. 9 | templates_path = ['_templates'] 10 | 11 | source_suffix = ['.rst'] 12 | 13 | # The master toctree document. 14 | master_doc = 'index' 15 | 16 | # General information about the project. 17 | project = 'Mapping High Level Constructs to LLVM IR' 18 | author = 'Michael Rodler and Mikael Egevig' 19 | copyright = '2014-2023 ' + author 20 | 21 | # The short X.Y version. 22 | version = '' 23 | # The full version, including alpha/beta/rc tags. 24 | release = '' 25 | 26 | # The language for content autogenerated by Sphinx. Refer to documentation 27 | # for a list of supported languages. 28 | # 29 | # This is also used if you do content translation via gettext catalogs. 30 | # Usually you set "language" from the command line for these cases. 31 | language = "en" 32 | 33 | # List of patterns, relative to source directory, that match files and 34 | # directories to ignore when looking for source files. 35 | # This patterns also effect to html_static_path and html_extra_path 36 | exclude_patterns = [ 37 | '_build', 'Thumbs.db', '.DS_Store', 'node_modules', '_original_post' 38 | ] 39 | 40 | # The name of the Pygments (syntax highlighting) style to use. 41 | pygments_style = 'sphinx' 42 | 43 | # If true, `todo` and `todoList` produce output, else they produce nothing. 44 | todo_include_todos = True 45 | 46 | # -- Options for HTML output ---------------------------------------------- 47 | 48 | # The theme to use for HTML and HTML Help pages. See the documentation for 49 | # a list of builtin themes. 50 | # 51 | html_theme = 'sphinx_rtd_theme' 52 | 53 | # Theme options are theme-specific and customize the look and feel of a theme 54 | # further. For a list of options available for each theme, see the 55 | # documentation. 56 | # 57 | # html_theme_options = {} 58 | 59 | # Add any paths that contain custom static files (such as style sheets) here, 60 | # relative to this directory. They are copied after the builtin static files, 61 | # so a file named "default.css" will overwrite the builtin "default.css". 62 | html_static_path = ['_static'] 63 | 64 | # -- Options for HTMLHelp output ------------------------------------------ 65 | 66 | # Output file base name for HTML help builder. 67 | htmlhelp_basename = 'MappingHighLevelConstructstoLLVMIRdoc' 68 | 69 | # -- Options for LaTeX output --------------------------------------------- 70 | 71 | latex_elements = { 72 | # The paper size ('letterpaper' or 'a4paper'). 73 | # 74 | # 'papersize': 'letterpaper', 75 | 76 | # The font size ('10pt', '11pt' or '12pt'). 77 | # 78 | # 'pointsize': '10pt', 79 | 80 | # Additional stuff for the LaTeX preamble. 81 | # 82 | # 'preamble': '', 83 | 84 | # Latex figure (float) alignment 85 | # 86 | # 'figure_align': 'htbp', 87 | } 88 | 89 | # Grouping the document tree into LaTeX files. List of tuples 90 | # (source start file, target name, title, 91 | # author, documentclass [howto, manual, or own class]). 92 | latex_documents = [ 93 | (master_doc, 'MappingHighLevelConstructstoLLVMIR.tex', 94 | 'Mapping High Level Constructs to LLVM IR Documentation', 'Test', 95 | 'manual'), 96 | ] 97 | 98 | # -- Options for manual page output --------------------------------------- 99 | 100 | # One entry per manual page. List of tuples 101 | # (source start file, name, description, authors, manual section). 102 | man_pages = [(master_doc, 'mappinghighlevelconstructstollvmir', 103 | 'Mapping High Level Constructs to LLVM IR Documentation', 104 | [author], 1)] 105 | 106 | # -- Options for Texinfo output ------------------------------------------- 107 | 108 | # Grouping the document tree into Texinfo files. List of tuples 109 | # (source start file, target name, title, author, 110 | # dir menu entry, description, category) 111 | texinfo_documents = [ 112 | (master_doc, 'MappingHighLevelConstructstoLLVMIR', 113 | 'Mapping High Level Constructs to LLVM IR Documentation', author, 114 | 'MappingHighLevelConstructstoLLVMIR', 'One line description of project.', 115 | 'Miscellaneous'), 116 | ] 117 | 118 | # -- Options for Epub output ---------------------------------------------- 119 | 120 | # Bibliographic Dublin Core info. 121 | epub_title = project 122 | epub_author = author 123 | epub_publisher = author 124 | epub_copyright = copyright 125 | 126 | # The unique identifier of the text. This can be a ISBN number 127 | # or the project homepage. 128 | # 129 | # epub_identifier = '' 130 | 131 | # A unique identification for the text. 132 | # 133 | # epub_uid = '' 134 | 135 | # A list of files that should not be packed into the epub file. 136 | epub_exclude_files = ['search.html'] 137 | -------------------------------------------------------------------------------- /control-structures/if-then-else.rst: -------------------------------------------------------------------------------- 1 | Simple "if-then-else" Branching 2 | ------------------------------- 3 | 4 | First let's take a look at a very simple function, that computes the 5 | maximum of two integers. This is implemented using a single if control 6 | statement. 7 | 8 | .. literalinclude:: listings/simple_if_max.cpp 9 | :language: c++ 10 | 11 | Remember that in LLVM IR control-flow is implemented by jumping between 12 | *basic blocks*, which contain instruction sequences that do not change 13 | control flow. Each basic block ends with an instruction that changes the 14 | control flow. The most common branching instruction is 15 | ``br`` [#brlink]_. ``br`` can be used conditionally, then it 16 | implements a simple if-then-else, taking a boolean condition flag and 17 | two basic block labels as parameter. 18 | 19 | .. code-block:: llvm 20 | 21 | br i1 %cond, label %iftrue, label %iffalse 22 | 23 | ``br`` can also be used to unconditionally jump to a certain destination: 24 | 25 | .. code-block:: llvm 26 | 27 | br label %dest 28 | 29 | .. literalinclude:: listings/simple_if_max_cleaned.ll 30 | :language: llvm 31 | 32 | In the example above, there are 4 basic blocks. The first one is the 33 | function entry block. There space is allocated on the stack with 34 | ``alloca`` [#allocalink]_, which acts as a temporary storage for the bigger value. Then 35 | the two parameter ``%a`` and ``%b`` are compared using the 36 | ``icmp`` instruction [#icmplink]_. The result is a boolean 37 | (``i1``) flag, which is then used as condition for the ``br`` 38 | instruction. Then depending on the taken branch, either ``%a`` or ``%b`` 39 | is stored into the temporary ``%retval`` variable. Each of the branches 40 | then end with a unconditional branch to the last basic block ``%end``. 41 | There the value from ``%retval`` is loaded and returned. 42 | 43 | You can get a graphical representation of the control-flow in the form 44 | of a control-flow graph (CFG). This can be generated by using 45 | ``opt -dot-cfg input.ll``. 46 | 47 | .. figure:: listings/simple_if_max_cleaned_cfg.png 48 | :alt: Control-Flow Graph of the max function 49 | 50 | Control-Flow Graph of the max function 51 | 52 | LLVM IR is a rather rich intermediate code format. So when compiling the 53 | above snippet with higher optimization levels, LLVM will optimize the 54 | code to use the ``select`` instruction [#selectlink]_ instead 55 | of generating branches. The ``select`` instruction simply chooses 56 | between two values, based on a boolean condition. This shortens the code 57 | significantly. 58 | 59 | .. literalinclude:: listings/simple_if_max_O1_cleaned.ll 60 | :language: llvm 61 | 62 | 63 | .. [#allocalink] `LangRef: alloca `__ 64 | .. [#brlink] `LangRef: br `__ 65 | .. [#icmplink] `LangRef: icmp `__ 66 | .. [#selectlink] `LangRef: select `__ 67 | -------------------------------------------------------------------------------- /control-structures/index.rst: -------------------------------------------------------------------------------- 1 | *********************** 2 | Control-Flow Constructs 3 | *********************** 4 | 5 | Similar to low-level assembly languages, LLVM's IR consists of sequences 6 | of instructions, that are executed sequentially. The instructions are 7 | grouped together to form *basic blocks*. Each basic block terminates 8 | with an instruction that changes the control flow of the program. 9 | 10 | .. toctree:: 11 | :hidden: 12 | :caption: Contents: 13 | 14 | if-then-else 15 | ssa-phi 16 | 17 | -------------------------------------------------------------------------------- /control-structures/listings/Makefile: -------------------------------------------------------------------------------- 1 | include ../../common.mk 2 | 3 | simple_if_max_cleaned_cfg.png: simple_if_max_cleaned.ll 4 | opt -dot-cfg simple_if_max_cleaned.ll >/dev/null 5 | # remove label 6 | sed -i 's/ *label="CFG.\+//g' cfg.max.dot 7 | dot -Tpng cfg.max.dot > simple_if_max_cleaned_cfg.png 8 | -------------------------------------------------------------------------------- /control-structures/listings/simple_if_max.cpp: -------------------------------------------------------------------------------- 1 | int max(int a, int b) { 2 | if (a > b) { 3 | return a; 4 | } else { 5 | return b; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /control-structures/listings/simple_if_max_O1_cleaned.ll: -------------------------------------------------------------------------------- 1 | define i32 @max(i32 %a, i32 %b) { 2 | %1 = icmp sgt i32 %a, %b 3 | %2 = select i1 %1, i32 %a, i32 %b 4 | ret i32 %2 5 | } 6 | -------------------------------------------------------------------------------- /control-structures/listings/simple_if_max_cleaned.ll: -------------------------------------------------------------------------------- 1 | define i32 @max(i32 %a, i32 %b) { 2 | entry: 3 | %retval = alloca i32, align 4 4 | %0 = icmp sgt i32 %a, %b 5 | br i1 %0, label %btrue, label %bfalse 6 | 7 | btrue: ; preds = %2 8 | store i32 %a, i32* %retval, align 4 9 | br label %end 10 | 11 | bfalse: ; preds = %2 12 | store i32 %b, i32* %retval, align 4 13 | br label %end 14 | 15 | end: ; preds = %btrue, %bfalse 16 | %1 = load i32, i32* %retval, align 4 17 | ret i32 %1 18 | } 19 | -------------------------------------------------------------------------------- /control-structures/listings/simple_if_max_cleaned_cfg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f0rki/mapping-high-level-constructs-to-llvm-ir/716de12f9ab44d526c467d8bc79db4225e983364/control-structures/listings/simple_if_max_cleaned_cfg.png -------------------------------------------------------------------------------- /control-structures/listings/simple_if_max_phi.ll: -------------------------------------------------------------------------------- 1 | define i32 @max(i32 %a, i32 %b) { 2 | entry: 3 | %0 = icmp sgt i32 %a, %b 4 | br i1 %0, label %btrue, label %bfalse 5 | 6 | btrue: ; preds = %2 7 | br label %end 8 | 9 | bfalse: ; preds = %2 10 | br label %end 11 | 12 | end: ; preds = %btrue, %bfalse 13 | %retval = phi i32 [%a, %btrue], [%b, %bfalse] 14 | ret i32 %retval 15 | } 16 | -------------------------------------------------------------------------------- /control-structures/ssa-phi.rst: -------------------------------------------------------------------------------- 1 | Single-Static Assignment Form and PHI 2 | ------------------------------------- 3 | 4 | We'll take a look at the same very simple ``max`` function, as in the previous 5 | section. 6 | 7 | .. literalinclude:: listings/simple_if_max.cpp 8 | :language: c++ 9 | 10 | Translated to LLVM IR: 11 | 12 | .. literalinclude:: listings/simple_if_max_cleaned.ll 13 | :language: llvm 14 | 15 | We can see that the function allocates space on the stack with ``alloca`` 16 | [#allocalink]_, where the bigger value is stored. In one branch ``%a`` is 17 | stored, while in the other branch ``%b`` is stored to the stack allocated 18 | memory. However, we want to avoid using memory load/store operation and use 19 | registers instead, whenever possible. So we would like to write something like 20 | this: 21 | 22 | .. code-block:: llvm 23 | 24 | define i32 @max(i32 %a, i32 %b) { 25 | entry: 26 | %0 = icmp sgt i32 %a, %b 27 | br i1 %0, label %btrue, label %bfalse 28 | 29 | btrue: 30 | %retval = %a 31 | br label %end 32 | 33 | bfalse: 34 | %retval = %b 35 | br label %end 36 | 37 | end: 38 | ret i32 %retval 39 | } 40 | 41 | This is not valid LLVM IR, because it violates the static single assignment 42 | form (SSA, [#wikissa]_) of the LLVM IR. SSA form requires that every variable 43 | is assigned only exactly once. SSA form enables and simplifies a vast number of 44 | compiler optimizations, and is the de-facto standard for intermediate 45 | representations in compilers of imperative programming languages. 46 | 47 | Now how would one implement the above code in proper SSA form LLVM IR? The 48 | answer is the magic ``phi`` instruction. The ``phi`` instruction is named after 49 | the φ function used in the theory of SSA. This functions magically chooses the 50 | right value, depending on the control flow. In LLVM you have to manually 51 | specify the name of the value and the previous basic block. 52 | 53 | .. code-block:: llvm 54 | 55 | end: 56 | %retval = phi i32 [%a, %btrue], [%b, %bfalse] 57 | 58 | Here we instruct the ``phi`` instruction to choose ``%a`` if the previous basic 59 | block was ``%btrue``. If the previous basic block was ``%bfalse``, then ``%b`` 60 | will be used. The value is then assigned to a new variable ``%retval``. Here 61 | you can see the full code listing: 62 | 63 | .. literalinclude:: listings/simple_if_max_phi.ll 64 | :language: llvm 65 | 66 | 67 | PHI in the Back End 68 | ~~~~~~~~~~~~~~~~~~~ 69 | 70 | Let's have a look how the ``@max`` function now maps to actual machine code. 71 | We'll have a look what kind of assembly code is generated by the compiler back 72 | end. In this case we'll look at the code generated for x86 64-bit, compiled 73 | with different optimization levels. We'll start with a non-optimizing backend 74 | (``llc -O0 -filetype=asm``). We will get something like this assembly: 75 | 76 | .. code-block:: asm 77 | 78 | max: # @max 79 | # %bb.0: # %entry 80 | cmpl %esi, %edi # %edi = %a, %esi = %b 81 | jle .LBB0_2 82 | # %bb.1: # %btrue 83 | movl %edi, -4(%rsp) # mov src, dst 84 | jmp .LBB0_3 85 | .LBB0_2: # %bfalse 86 | movl %esi, -4(%rsp) # mov src, dst 87 | jmp .LBB0_3 88 | .LBB0_3: # %end 89 | movl -4(%rsp), %eax # return value in eax 90 | retq 91 | 92 | 93 | The parameters ``%a`` and ``%b`` are passed in ``%edi`` and ``%esi`` 94 | respectively. We can see that the compiler back end generated code that uses 95 | the stack to store the bigger value. So the code generated by the compiler back 96 | end is not what we had in mind, when we wrote the LLVM IR. The reason for this 97 | is that the compiler back end needs to implement the ``phi`` instruction with 98 | real machine instructions. Usually that is done by assigning to one register or 99 | storing to one common stack memory location. Usually the compiler back end will 100 | use the stack for implementing the ``phi`` instruction. However, if we use a 101 | little more optimization in the back end (i.e., ``llc -O1``), we can get a more 102 | optimized version: 103 | 104 | .. code-block:: asm 105 | 106 | max: # @max 107 | # %bb.0: # %entry 108 | cmpl %esi, %edi 109 | jg .LBB0_2 110 | # %bb.1: # %bfalse 111 | movl %esi, %edi 112 | .LBB0_2: # %end 113 | movl %edi, %eax 114 | retq 115 | 116 | 117 | Here the ``phi`` function is implemented by using the ``%edi`` register. In one 118 | branch ``%edi`` already contains the desired value, so nothing happens. In the 119 | other branch ``%esi`` is copied to ``%edi``. At the ``%end`` basic block, 120 | ``%edi`` contains the desired value from both branches. This is more like what 121 | we had in mind. We can see that optimization is something that needs to be 122 | applied through the whole compilation pipeline. 123 | 124 | 125 | .. [#wikissa] `Wikipedia: Static single assignment form `__ 126 | .. [#allocalink] `LangRef: alloca `__ 127 | .. [#philink] `LangRef: phi `__ 128 | -------------------------------------------------------------------------------- /epilogue/contribution.rst: -------------------------------------------------------------------------------- 1 | Contribution 2 | ============ 3 | 4 | If you want to contribute to this document you can: 5 | 6 | - `Create an issue on 7 | Github `__ 8 | - Fork and fix it yourself. We're happy to merge any pull requests or 9 | accept patches. 10 | 11 | Thank You 12 | --------- 13 | 14 | A brief list of all people who've contributed to the document (thank you 15 | all very much!): 16 | 17 | - Michael Rodler (current maintainer and back-porter from MeWeb markup 18 | to GitHub markdown). 19 | - Mikael Egevig (author of the original document). 20 | - Dirkjan Ochtman (basically all the generator-related stuff by giving 21 | us some crucial samples). 22 | - Eli Bendersky (for small grammar fixes and mention of ``opt``'s 23 | ``.bc`` output). 24 | - Sean Silva (for using proper C++11 lambda syntax in lambda samples). 25 | - Isaac Dupree (for correction the name of '@': It is "at-sign", not 26 | "ampersand"). 27 | - Wilfred Hughes (``i`` became ``index`` and addition of separator 28 | between generator C++ and LLVM IR code). 29 | - Kenneth Ho (correction to C++11 lambda example and C++ exception 30 | handling sample). 31 | - Xing GUO (correction to various typos, updates to LLVM 8 syntax) 32 | 33 | Should your name be here? If so, contribute :-) 34 | -------------------------------------------------------------------------------- /epilogue/index.rst: -------------------------------------------------------------------------------- 1 | Epilogue 2 | ======== 3 | 4 | Remember that you can learn a lot by using the ``-emit-llvm`` option to 5 | the ``clang``/``clang++`` compiler. This gives you a chance to see a 6 | live production compiler in action and how it precisely does things. 7 | 8 | If you discover something new this way, or any errors in this document 9 | or you need more information than given here, please create `an issue at 10 | Github `__ 11 | 12 | .. toctree:: 13 | :hidden: 14 | 15 | resources 16 | contribution 17 | -------------------------------------------------------------------------------- /epilogue/resources.rst: -------------------------------------------------------------------------------- 1 | Further Reading 2 | =============== 3 | 4 | This chapter lists some resources that may be of interest to the reader: 5 | 6 | - LLVM documentation http://llvm.org/docs/ 7 | - Modern Compiler Implementation in Java, 2nd Edition. 8 | - Eli Bendersky's collection of code examples for using LLVM/clang, 9 | https://github.com/eliben/llvm-clang-samples 10 | - "How Clang Compiles a Function" by John Regehr, June 2018, 11 | https://blog.regehr.org/archives/1605 12 | 13 | .. - `Alex Darby's series of articles on low-level stuff `__. 14 | -------------------------------------------------------------------------------- /exception-handling/exception-handling-by-propagated-return-value.rst: -------------------------------------------------------------------------------- 1 | Exception Handling by Propagated Return Value 2 | --------------------------------------------- 3 | 4 | This method is a compiler-generated way of implicitly checking each 5 | function's return value. Its main advantage is that it is simple - at 6 | the cost of many mostly unproductive checks of return values. The great 7 | thing about this method is that it readily interfaces with a host of 8 | languages and environments - it is all a matter of returning a pointer 9 | to an exception. 10 | 11 | The C++ example from the beginning of the section maps to the following 12 | code: 13 | 14 | .. literalinclude:: listings/propagated_return_values.ll 15 | :language: llvm 16 | -------------------------------------------------------------------------------- /exception-handling/index.rst: -------------------------------------------------------------------------------- 1 | Exception Handling 2 | ================== 3 | 4 | Exceptions can be implemented in one of three ways: 5 | 6 | - The simple way, by using a propagated return value. 7 | - The bulky way, by using ``setjmp`` and ``longjmp``. 8 | - The efficient way, by using a zero-cost exception ABI. 9 | 10 | Please notice that many compiler developers with respect for themselves 11 | won't accept the first method as a proper way of handling exceptions. 12 | However, it is unbeatable in terms of simplicity and can likely help 13 | people to understand that implementing exceptions does not need to be 14 | very difficult. 15 | 16 | The second method is used by some production compilers, but it has large 17 | overhead both in terms of code bloat and the cost of a ``try-catch`` 18 | statement (because all CPU registers are saved using ``setjmp`` whenever 19 | a ``try`` statement is encountered). 20 | 21 | The third method is very advanced but in return does not add any cost to 22 | execution paths where no exceptions are being thrown. This method is the 23 | de-facto "right" way of implementing exceptions, whether you like it or 24 | not. LLVM directly supports this kind of exception handling. 25 | 26 | In the three sections below, we'll be using this sample and transform 27 | it: 28 | 29 | .. literalinclude:: listings/exception_example.cpp 30 | :language: c++ 31 | 32 | 33 | .. toctree:: 34 | :hidden: 35 | 36 | exception-handling-by-propagated-return-value 37 | setjmp+longjmp-exception-handling 38 | zero-cost-exception-handling 39 | resources 40 | -------------------------------------------------------------------------------- /exception-handling/listings/exception_example.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class Object { 5 | public: 6 | virtual ~Object() {} 7 | }; 8 | 9 | class Exception : public Object { 10 | public: 11 | Exception(const char* text) 12 | : _text(text) 13 | { 14 | } 15 | 16 | const char* GetText() const { return _text; } 17 | 18 | private: 19 | const char* _text; 20 | }; 21 | 22 | class Foo { 23 | public: 24 | int GetLength() const { return _length; } 25 | 26 | void SetLength(int value) { _length = value; } 27 | 28 | private: 29 | int _length; 30 | }; 31 | 32 | int Bar(bool fail) 33 | { 34 | Foo foo; 35 | foo.SetLength(17); 36 | if (fail) 37 | throw new Exception("Exception requested by caller"); 38 | foo.SetLength(24); 39 | return foo.GetLength(); 40 | } 41 | 42 | int main(int argc, const char* argv[]) 43 | { 44 | int result; 45 | 46 | try { 47 | /* The program throws an exception if an argument is specified. */ 48 | bool fail = (argc >= 2); 49 | 50 | /* Let callee decide if an exception is thrown. */ 51 | int value = Bar(fail); 52 | 53 | result = EXIT_SUCCESS; 54 | } catch (Exception* that) { 55 | printf("Error: %s\n", that->GetText()); 56 | result = EXIT_FAILURE; 57 | } catch (...) { 58 | puts("Internal error: Unhandled exception detected"); 59 | result = EXIT_FAILURE; 60 | } 61 | 62 | return result; 63 | } 64 | -------------------------------------------------------------------------------- /exception-handling/listings/propagated_return_values.ll: -------------------------------------------------------------------------------- 1 | ;********************* External and Utility functions ********************* 2 | 3 | declare i8* @malloc(i32) nounwind 4 | declare void @free(i8*) nounwind 5 | declare i32 @printf(i8* noalias nocapture, ...) nounwind 6 | declare i32 @puts(i8* noalias nocapture) nounwind 7 | 8 | ;***************************** Object class ******************************* 9 | 10 | %Object_vtable_type = type { 11 | %Object_vtable_type*, ; 0: above: parent class vtable pointer 12 | i8* ; 1: class: class name (usually mangled) 13 | ; virtual methods would follow here 14 | } 15 | 16 | @.Object_class_name = private constant [7 x i8] c"Object\00" 17 | 18 | @.Object_vtable = private constant %Object_vtable_type { 19 | %Object_vtable_type* null, ; This is the root object of the object hierarchy 20 | i8* getelementptr([7 x i8], [7 x i8]* @.Object_class_name, i32 0, i32 0) 21 | } 22 | 23 | %Object = type { 24 | %Object_vtable_type* ; 0: vtable: class vtable pointer (always non-null) 25 | ; class data members would follow here 26 | } 27 | 28 | ; returns true if the specified object is identical to or derived from the 29 | ; class with the specified name. 30 | define i1 @Object_IsA(%Object* %object, i8* %name) nounwind { 31 | .init: 32 | ; if (object == null) return false 33 | %0 = icmp ne %Object* %object, null 34 | br i1 %0, label %.once, label %.exit_false 35 | 36 | .once: 37 | %1 = getelementptr %Object, %Object* %object, i32 0, i32 0 38 | br label %.body 39 | 40 | .body: 41 | ; if (vtable->class == name) 42 | %2 = phi %Object_vtable_type** [ %1, %.once ], [ %7, %.next] 43 | %3 = load %Object_vtable_type*, %Object_vtable_type** %2 44 | %4 = getelementptr %Object_vtable_type, %Object_vtable_type* %3, i32 0, i32 1 45 | %5 = load i8*, i8** %4 46 | %6 = icmp eq i8* %5, %name 47 | br i1 %6, label %.exit_true, label %.next 48 | 49 | .next: 50 | ; object = object->above 51 | %7 = getelementptr %Object_vtable_type, %Object_vtable_type* %3, i32 0, i32 0 52 | 53 | ; while (object != null) 54 | %8 = icmp ne %Object_vtable_type* %3, null 55 | br i1 %8, label %.body, label %.exit_false 56 | 57 | .exit_true: 58 | ret i1 true 59 | 60 | .exit_false: 61 | ret i1 false 62 | } 63 | 64 | ;*************************** Exception class ****************************** 65 | 66 | %Exception_vtable_type = type { 67 | %Object_vtable_type*, ; 0: parent class vtable pointer 68 | i8* ; 1: class name 69 | ; virtual methods would follow here. 70 | } 71 | 72 | @.Exception_class_name = private constant [10 x i8] c"Exception\00" 73 | 74 | @.Exception_vtable = private constant %Exception_vtable_type { 75 | %Object_vtable_type* @.Object_vtable, ; the parent of this class is the Object class 76 | i8* getelementptr([10 x i8], [10 x i8]* @.Exception_class_name, i32 0, i32 0) 77 | } 78 | 79 | %Exception = type { 80 | %Exception_vtable_type*, ; 0: the vtable pointer 81 | i8* ; 1: the _text member 82 | } 83 | 84 | define void @Exception_Create_String(%Exception* %this, i8* %text) nounwind { 85 | ; set up vtable 86 | %1 = getelementptr %Exception, %Exception* %this, i32 0, i32 0 87 | store %Exception_vtable_type* @.Exception_vtable, %Exception_vtable_type** %1 88 | 89 | ; save input text string into _text 90 | %2 = getelementptr %Exception, %Exception* %this, i32 0, i32 1 91 | store i8* %text, i8** %2 92 | 93 | ret void 94 | } 95 | 96 | define i8* @Exception_GetText(%Exception* %this) nounwind { 97 | %1 = getelementptr %Exception, %Exception* %this, i32 0, i32 1 98 | %2 = load i8*, i8** %1 99 | ret i8* %2 100 | } 101 | 102 | ;******************************* Foo class ******************************** 103 | 104 | %Foo = type { i32 } 105 | 106 | define void @Foo_Create_Default(%Foo* %this) nounwind { 107 | %1 = getelementptr %Foo, %Foo* %this, i32 0, i32 0 108 | store i32 0, i32* %1 109 | ret void 110 | } 111 | 112 | define i32 @Foo_GetLength(%Foo* %this) nounwind { 113 | %1 = getelementptr %Foo, %Foo* %this, i32 0, i32 0 114 | %2 = load i32, i32* %1 115 | ret i32 %2 116 | } 117 | 118 | define void @Foo_SetLength(%Foo* %this, i32 %value) nounwind { 119 | %1 = getelementptr %Foo, %Foo* %this, i32 0, i32 0 120 | store i32 %value, i32* %1 121 | ret void 122 | } 123 | 124 | ;********************************* Foo function *************************** 125 | 126 | @.message1 = internal constant [30 x i8] c"Exception requested by caller\00" 127 | 128 | define %Exception* @Bar(i1 %fail, i32* %result) nounwind { 129 | ; Allocate Foo instance 130 | %foo = alloca %Foo 131 | call void @Foo_Create_Default(%Foo* %foo) 132 | 133 | call void @Foo_SetLength(%Foo* %foo, i32 17) 134 | 135 | ; if (fail) 136 | %1 = icmp eq i1 %fail, true 137 | br i1 %1, label %.if_begin, label %.if_close 138 | 139 | .if_begin: 140 | ; throw new Exception(...) 141 | %2 = call i8* @malloc(i32 8) 142 | %3 = bitcast i8* %2 to %Exception* 143 | %4 = getelementptr [30 x i8], [30 x i8]* @.message1, i32 0, i32 0 144 | call void @Exception_Create_String(%Exception* %3, i8* %4) 145 | ret %Exception* %3 146 | 147 | .if_close: 148 | ; foo.SetLength(24) 149 | call void @Foo_SetLength(%Foo* %foo, i32 24) 150 | %5 = call i32 @Foo_GetLength(%Foo* %foo) 151 | store i32 %5, i32* %result 152 | ret %Exception* null 153 | } 154 | 155 | ;********************************* Main program *************************** 156 | 157 | @.message2 = internal constant [11 x i8] c"Error: %s\0A\00" 158 | @.message3 = internal constant [44 x i8] c"Internal error: Unhandled exception detectd\00" 159 | 160 | define i32 @main(i32 %argc, i8** %argv) nounwind { 161 | ; "try" keyword expands to nothing. 162 | 163 | ; Body of try block. 164 | 165 | ; fail = (argc >= 2) 166 | %fail = icmp uge i32 %argc, 2 167 | 168 | ; Function call. 169 | %1 = alloca i32 170 | %2 = call %Exception* @Bar(i1 %fail, i32* %1) 171 | %3 = icmp ne %Exception* %2, null 172 | br i1 %3, label %.catch_block, label %.exit 173 | 174 | .catch_block: 175 | %4 = bitcast %Exception* %2 to %Object* 176 | %5 = getelementptr [10 x i8], [10 x i8]* @.Exception_class_name, i32 0, i32 0 177 | %6 = call i1 @Object_IsA(%Object* %4, i8* %5) 178 | br i1 %6, label %.catch_exception, label %.catch_all 179 | 180 | .catch_exception: 181 | %7 = getelementptr [11 x i8], [11 x i8]* @.message2, i32 0, i32 0 182 | %8 = call i8* @Exception_GetText(%Exception* %2) 183 | %9 = call i32 (i8*, ...) @printf(i8* %7, i8* %8) 184 | br label %.exit 185 | 186 | .catch_all: 187 | %10 = getelementptr [44 x i8], [44 x i8]* @.message3, i32 0, i32 0 188 | %11 = call i32 @puts(i8* %10) 189 | br label %.exit 190 | 191 | .exit: 192 | %result = phi i32 [ 0, %0 ], [ 1, %.catch_exception ], [ 1, %.catch_all ] 193 | ret i32 %result 194 | } 195 | -------------------------------------------------------------------------------- /exception-handling/listings/setjmp_longjmp.ll: -------------------------------------------------------------------------------- 1 | ; jmp_buf is very platform specific, this is for illustration only... 2 | %jmp_buf = type [ 5 x i32 ] 3 | declare i32 @setjmp(%jmp_buf* %env) 4 | declare void @longjmp(%jmp_buf* %env, i32 %val) 5 | 6 | ;********************* External and Utility functions ********************* 7 | 8 | declare i8* @malloc(i32) nounwind 9 | declare void @free(i8*) nounwind 10 | declare i32 @printf(i8* noalias nocapture, ...) nounwind 11 | declare i32 @puts(i8* noalias nocapture) nounwind 12 | 13 | ;***************************** Object class ******************************* 14 | 15 | %Object_vtable_type = type { 16 | %Object_vtable_type*, ; 0: above: parent class vtable pointer 17 | i8* ; 1: class: class name (usually mangled) 18 | ; virtual methods would follow here 19 | } 20 | 21 | @.Object_class_name = private constant [7 x i8] c"Object\00" 22 | 23 | @.Object_vtable = private constant %Object_vtable_type { 24 | %Object_vtable_type* null, ; This is the root object of the object hierarchy 25 | i8* getelementptr([7 x i8]* @.Object_class_name, i32 0, i32 0) 26 | } 27 | 28 | %Object = type { 29 | %Object_vtable_type* ; 0: vtable: class vtable pointer (always non-null) 30 | ; class data members would follow here 31 | } 32 | 33 | ; returns true if the specified object is identical to or derived from the 34 | ; class with the specified name. 35 | define i1 @Object_IsA(%Object* %object, i8* %name) nounwind { 36 | .init: 37 | ; if (object == null) return false 38 | %0 = icmp ne %Object* %object, null 39 | br i1 %0, label %.once, label %.exit_false 40 | 41 | .once: 42 | %1 = getelementptr %Object* %object, i32 0, i32 0 43 | br label %.body 44 | 45 | .body: 46 | ; if (vtable->class == name) 47 | %2 = phi %Object_vtable_type** [ %1, %.once ], [ %7, %.next] 48 | %3 = load %Object_vtable_type** %2 49 | %4 = getelementptr %Object_vtable_type* %3, i32 0, i32 1 50 | %5 = load i8** %4 51 | %6 = icmp eq i8* %5, %name 52 | br i1 %6, label %.exit_true, label %.next 53 | 54 | .next: 55 | ; object = object->above 56 | %7 = getelementptr %Object_vtable_type* %3, i32 0, i32 0 57 | 58 | ; while (object != null) 59 | %8 = icmp ne %Object_vtable_type* %3, null 60 | br i1 %8, label %.body, label %.exit_false 61 | 62 | .exit_true: 63 | ret i1 true 64 | 65 | .exit_false: 66 | ret i1 false 67 | } 68 | 69 | ;*************************** Exception class ****************************** 70 | 71 | %Exception_vtable_type = type { 72 | %Object_vtable_type*, ; 0: parent class vtable pointer 73 | i8* ; 1: class name 74 | ; virtual methods would follow here. 75 | } 76 | 77 | @.Exception_class_name = private constant [10 x i8] c"Exception\00" 78 | 79 | @.Exception_vtable = private constant %Exception_vtable_type { 80 | %Object_vtable_type* @.Object_vtable, ; the parent of this class is the Object class 81 | i8* getelementptr([10 x i8]* @.Exception_class_name, i32 0, i32 0) 82 | } 83 | 84 | %Exception = type { 85 | %Exception_vtable_type*, ; 0: the vtable pointer 86 | i8* ; 1: the _text member 87 | } 88 | 89 | define void @Exception_Create_String(%Exception* %this, i8* %text) nounwind { 90 | ; set up vtable 91 | %1 = getelementptr %Exception* %this, i32 0, i32 0 92 | store %Exception_vtable_type* @.Exception_vtable, %Exception_vtable_type** %1 93 | 94 | ; save input text string into _text 95 | %2 = getelementptr %Exception* %this, i32 0, i32 1 96 | store i8* %text, i8** %2 97 | 98 | ret void 99 | } 100 | 101 | define i8* @Exception_GetText(%Exception* %this) nounwind { 102 | %1 = getelementptr %Exception* %this, i32 0, i32 1 103 | %2 = load i8** %1 104 | ret i8* %2 105 | } 106 | 107 | ;******************************* Foo class ******************************** 108 | 109 | %Foo = type { i32 } 110 | 111 | define void @Foo_Create_Default(%Foo* %this) nounwind { 112 | %1 = getelementptr %Foo* %this, i32 0, i32 0 113 | store i32 0, i32* %1 114 | ret void 115 | } 116 | 117 | define i32 @Foo_GetLength(%Foo* %this) nounwind { 118 | %1 = getelementptr %Foo* %this, i32 0, i32 0 119 | %2 = load i32* %1 120 | ret i32 %2 121 | } 122 | 123 | define void @Foo_SetLength(%Foo* %this, i32 %value) nounwind { 124 | %1 = getelementptr %Foo* %this, i32 0, i32 0 125 | store i32 %value, i32* %1 126 | ret void 127 | } 128 | 129 | ;********************************* Foo function *************************** 130 | 131 | @.message1 = internal constant [30 x i8] c"Exception requested by caller\00" 132 | 133 | define i32 @Bar(%jmp_buf* %throw, i1 %fail) nounwind { 134 | ; Allocate Foo instance 135 | %foo = alloca %Foo 136 | call void @Foo_Create_Default(%Foo* %foo) 137 | 138 | call void @Foo_SetLength(%Foo* %foo, i32 17) 139 | 140 | ; if (fail) 141 | %1 = icmp eq i1 %fail, true 142 | br i1 %1, label %.if_begin, label %.if_close 143 | 144 | .if_begin: 145 | ; throw new Exception(...) 146 | %2 = call i8* @malloc(i32 8) 147 | %3 = bitcast i8* %2 to %Exception* 148 | %4 = getelementptr [30 x i8]* @.message1, i32 0, i32 0 149 | call void @Exception_Create_String(%Exception* %3, i8* %4) 150 | %5 = ptrtoint %Exception* %3 to i32 151 | call void @longjmp(%jmp_buf* %throw, i32 %5) 152 | ; we never get here 153 | br label %.if_close 154 | 155 | .if_close: 156 | ; foo.SetLength(24) 157 | call void @Foo_SetLength(%Foo* %foo, i32 24) 158 | %6 = call i32 @Foo_GetLength(%Foo* %foo) 159 | ret i32 %6 160 | } 161 | 162 | ;********************************* Main program *************************** 163 | 164 | @.message2 = internal constant [11 x i8] c"Error: %s\0A\00" 165 | @.message3 = internal constant [44 x i8] c"Internal error: Unhandled exception detectd\00" 166 | 167 | define i32 @main(i32 %argc, i8** %argv) nounwind { 168 | ; "try" keyword expands to a call to @setjmp 169 | %env = alloca %jmp_buf 170 | %status = call i32 @setjmp(%jmp_buf* %env) 171 | %1 = icmp eq i32 %status, 0 172 | br i1 %1, label %.body, label %.catch_block 173 | 174 | .body: 175 | ; Body of try block. 176 | ; fail = (argc >= 2) 177 | %fail = icmp uge i32 %argc, 2 178 | 179 | ; Function call. 180 | %2 = call i32 @Bar(%jmp_buf* %env, i1 %fail) 181 | br label %.exit 182 | 183 | .catch_block: 184 | %3 = inttoptr i32 %status to %Object* 185 | %4 = getelementptr [10 x i8]* @.Exception_class_name, i32 0, i32 0 186 | %5 = call i1 @Object_IsA(%Object* %3, i8* %4) 187 | br i1 %5, label %.catch_exception, label %.catch_all 188 | 189 | .catch_exception: 190 | %6 = inttoptr i32 %status to %Exception* 191 | %7 = getelementptr [11 x i8]* @.message2, i32 0, i32 0 192 | %8 = call i8* @Exception_GetText(%Exception* %6) 193 | %9 = call i32 (i8*, ...)* @printf(i8* %7, i8* %8) 194 | br label %.exit 195 | 196 | .catch_all: 197 | %10 = getelementptr [44 x i8]* @.message3, i32 0, i32 0 198 | %11 = call i32 @puts(i8* %10) 199 | br label %.exit 200 | 201 | .exit: 202 | %result = phi i32 [ 0, %.body ], [ 1, %.catch_exception ], [ 1, %.catch_all ] 203 | ret i32 %result 204 | } 205 | -------------------------------------------------------------------------------- /exception-handling/resources.rst: -------------------------------------------------------------------------------- 1 | Resources 2 | --------- 3 | 4 | - `Compiler Internals - Exception Handling `_. 5 | - `Exception Handling in C without C++ `_. 6 | - `How a C++ Compiler Implements Exception Handling `_. 7 | - `DWARF standard - Exception Handling `_. 8 | - `Itanium C++ ABI `_. 9 | -------------------------------------------------------------------------------- /exception-handling/setjmp+longjmp-exception-handling.rst: -------------------------------------------------------------------------------- 1 | Setjmp/Longjmp Exception Handling 2 | --------------------------------- 3 | 4 | The basic idea behind the ``setjmp`` and ``longjmp`` exception handling 5 | scheme is that you save the CPU state whenever you encounter a ``try`` 6 | keyword and then do a ``longjmp`` whenever you throw an exception. If 7 | there are few ``try`` blocks in the program, as is typically the case, 8 | the cost of this method is not as high as it might seem. However, often 9 | there are implicit exception handlers due to the need to release local 10 | resources such as class instances allocated on the stack and then the 11 | cost can become quite high. 12 | 13 | ``setjmp``/``longjmp`` exception handling is often abbreviated ``SjLj`` 14 | for ``SetJmp``/``LongJmp``. 15 | 16 | Here is an example implementation of this kind of exception handling: 17 | 18 | .. literalinclude:: listings/setjmp_longjmp.ll 19 | :language: llvm 20 | 21 | Note that this example has been developed for a 32-bit architecture and passes 22 | a pointer to an exception instance instead of an error code as the second 23 | parameter of ``longjmp``. This trick abuses the fact that the `int` type has 24 | the same size as pointer types on 32-bit. This is not the case on 64-bit and as 25 | such, this example doesn't work on 64-bit architectures. 26 | -------------------------------------------------------------------------------- /exception-handling/zero-cost-exception-handling.rst: -------------------------------------------------------------------------------- 1 | Zero Cost Exception Handling 2 | ---------------------------- 3 | 4 | 5 | TODO 6 | -------------------------------------------------------------------------------- /index.rst: -------------------------------------------------------------------------------- 1 | Mapping High Level Constructs to LLVM IR 2 | ======================================== 3 | 4 | `Click here to read the book on 5 | readthedocs.org `__ 6 | 7 | About 8 | ----- 9 | 10 | This is a gitbook dedicated to providing a description on how LLVM based 11 | compilers map high-level language constructs into the LLVM intermediate 12 | representation (IR). 13 | 14 | This document targets people interested in how modern compilers work and 15 | want to learn how high-level language constructs can be implemented. 16 | Currently the books focuses on C and C++, but contributions about other 17 | languages targeting LLVM are highly welcome. This document should help 18 | to make the learning curve less steep for aspiring LLVM users. 19 | 20 | For the sake of simplicity, we'll be working with a 32-bit target 21 | machine so that pointers and word-sized operands are 32-bits. Also, for 22 | the sake of readability we do not mangle (encode) names. Rather, they 23 | are given simple, easy-to-read names that reflect their purpose. A 24 | production compiler for any language that supports overloading would 25 | generally need to mangle the names so as to avoid conflicts between 26 | symbols. 27 | 28 | Contributing 29 | ------------ 30 | 31 | The repository for this document is hosted on 32 | `github `__. 33 | All contributions are welcome. If you find an error file an 34 | `Issue `__ 35 | or fork the repository `and create a 36 | pull-request `__. 37 | 38 | License 39 | ------- 40 | 41 | UNLESS OTHERWISE NOTED, THE CONTENTS OF THIS REPOSITORY/DOCUMENT ARE LICENSED 42 | UNDER THE CREATIVE COMMONS ATTRIBUTION - SHARE ALIKE 4.0 INTERNATIONAL LICENSE 43 | 44 | .. figure:: https://i.creativecommons.org/l/by-sa/4.0/88x31.png 45 | :alt: https://creativecommons.org/licenses/by-sa/4.0/ 46 | 47 | https://creativecommons.org/licenses/by-sa/4.0/ 48 | 49 | 50 | .. toctree:: 51 | :maxdepth: 1 52 | :caption: Contents: 53 | 54 | a-quick-primer/index 55 | basic-constructs/index 56 | control-structures/index 57 | object-oriented-constructs/index 58 | exception-handling/index 59 | advanced-constructs/index 60 | interoperating-with-a-runtime-library/index 61 | interfacing-to-the-operating-system/index 62 | epilogue/index 63 | appendix-a-how-to-implement-a-string-type-in-llvm/index 64 | -------------------------------------------------------------------------------- /interfacing-to-the-operating-system/index.rst: -------------------------------------------------------------------------------- 1 | ******************************** 2 | Interfacing to Operating Systems 3 | ******************************** 4 | 5 | I'll divide this chapter into two sections: 6 | 7 | - How to Interface to POSIX Operating Systems. 8 | - How to Interface to the Windows Operating System. 9 | 10 | Interface to POSIX Operating Systems 11 | ==================================== 12 | 13 | On POSIX, the presence of the C run-time library is an unavoidable fact 14 | for which reason it makes a lot of sense to directly call such C 15 | run-time functions. 16 | 17 | Sample POSIX "Hello World" Application 18 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 19 | 20 | On POSIX, it is really very easy to create the ``Hello world`` program: 21 | 22 | .. code-block:: llvm 23 | 24 | declare i32 @puts(i8* nocapture) nounwind 25 | 26 | @.hello = private unnamed_addr constant [13 x i8] c"hello world\0A\00" 27 | 28 | define i32 @main(i32 %argc, i8** %argv) { 29 | %1 = getelementptr [13 x i8], [13 x i8]* @.hello, i32 0, i32 0 30 | call i32 @puts(i8* %1) 31 | ret i32 0 32 | } 33 | 34 | How to Interface to the Windows Operating System 35 | ================================================ 36 | 37 | On Windows, the C run-time library is mostly considered of relevance to 38 | the C and C++ languages only, so you have a plethora (thousands) of 39 | standard system interfaces that any client application may use. 40 | 41 | Sample Windows "Hello World" Application 42 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 43 | 44 | ``Hello world`` on Windows is nowhere as straightforward as on POSIX: 45 | 46 | .. literalinclude:: listings/windows.ll 47 | :language: llvm 48 | -------------------------------------------------------------------------------- /interfacing-to-the-operating-system/listings/listing_0.ll: -------------------------------------------------------------------------------- 1 | declare i32 @puts(i8* nocapture) nounwind 2 | 3 | @.hello = private unnamed_addr constant [13 x i8] c"hello world\0A\00" 4 | 5 | define i32 @main(i32 %argc, i8** %argv) { 6 | %1 = getelementptr [13 x i8]* @.hello, i32 0, i32 0 7 | call i32 @puts(i8* %1) 8 | ret i32 0 9 | } 10 | -------------------------------------------------------------------------------- /interfacing-to-the-operating-system/listings/windows.ll: -------------------------------------------------------------------------------- 1 | target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-f80:128:128-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32-S32" 2 | target triple = "i686-pc-win32" 3 | 4 | %struct._OVERLAPPED = type { i32, i32, %union.anon, i8* } 5 | %union.anon = type { %struct.anon } 6 | %struct.anon = type { i32, i32 } 7 | 8 | declare dllimport x86_stdcallcc i8* @"\01_GetStdHandle@4"(i32) #1 9 | 10 | declare dllimport x86_stdcallcc i32 @"\01_WriteFile@20"(i8*, i8*, i32, i32*, %struct._OVERLAPPED*) #1 11 | 12 | @hello = internal constant [13 x i8] c"Hello world\0A\00" 13 | 14 | define i32 @main(i32 %argc, i8** %argv) nounwind { 15 | %1 = call i8* @"\01_GetStdHandle@4"(i32 -11) ; -11 = STD_OUTPUT_HANDLE 16 | %2 = getelementptr [13 x i8], [13 x i8]* @.hello, i32 0, i32 0 17 | %3 = call i32 @"\01_WriteFile@20"(i8* %1, i8* %2, i32 12, i32* null, %struct._OVERLAPPED* null) 18 | ; todo: Check that %4 is not equal to -1 (INVALID_HANDLE_VALUE) 19 | ret i32 0 20 | } 21 | 22 | attributes #1 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" 23 | "no-infs-fp-math"="fa lse" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" 24 | "use-soft-float"="false" 25 | } 26 | -------------------------------------------------------------------------------- /interoperating-with-a-runtime-library/index.rst: -------------------------------------------------------------------------------- 1 | ************************************* 2 | Interoperating with a Runtime Library 3 | ************************************* 4 | 5 | It is common to provide a set of run-time support functions that are 6 | written in another language than LLVM IR and it is trivially easy to 7 | interface to such a run-time library. The use of ``malloc`` and ``free`` 8 | in the examples in this document are examples of such use of externally 9 | defined run-time functions. 10 | 11 | The advantages of a custom, non-IR run-time library function is that it 12 | can be optimized by hand to provide the best possible performance under 13 | certain criteria. Also a custom non-IR run-time library function can 14 | make explicit use of native instructions that are foreign to the LLVM 15 | infrastructure. 16 | 17 | The advantages of IR run-time library functions is that they can be run 18 | through the optimizer and thereby also be inlined automatically. 19 | -------------------------------------------------------------------------------- /make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | set SPHINXPROJ=MappingHighLevelConstructstoLLVMIR 13 | 14 | if "%1" == "" goto help 15 | 16 | %SPHINXBUILD% >NUL 2>NUL 17 | if errorlevel 9009 ( 18 | echo. 19 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 20 | echo.installed, then set the SPHINXBUILD environment variable to point 21 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 22 | echo.may add the Sphinx directory to PATH. 23 | echo. 24 | echo.If you don't have Sphinx installed, grab it from 25 | echo.http://sphinx-doc.org/ 26 | exit /b 1 27 | ) 28 | 29 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 30 | goto end 31 | 32 | :help 33 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 34 | 35 | :end 36 | popd 37 | -------------------------------------------------------------------------------- /object-oriented-constructs/boxing-and-unboxing.rst: -------------------------------------------------------------------------------- 1 | Boxing and Unboxing 2 | ------------------- 3 | 4 | Boxing is the process of converting a non-object primitive value into an 5 | object. It is as easy as it sounds. You create a wrapper class which you 6 | instantiate and initialize with the non-object value: 7 | 8 | Unboxing is the reverse of boxing: You downgrade a full object to a mere 9 | scalar value by retrieving the boxed value from the box object. 10 | 11 | It is important to notice that changes to the boxed value does not 12 | affect the original value and vice verse. The code below illustrates 13 | both steps: 14 | 15 | .. code-block:: llvm 16 | 17 | @Boxee = global i32 17 18 | 19 | %Integer = type { i32 } 20 | 21 | define void @Integer_Create(%Integer* %this, i32 %value) nounwind { 22 | ; you might set up a vtable and associated virtual methods here 23 | %1 = getelementptr %Integer, %Integer* %this, i32 0, i32 0 24 | store i32 %value, i32* %1 25 | ret void 26 | } 27 | 28 | define i32 @Integer_GetValue(%Integer* %this) nounwind { 29 | %1 = getelementptr %Integer, %Integer* %this, i32 0, i32 0 30 | %2 = load i32, i32* %1 31 | ret i32 %2 32 | } 33 | 34 | define i32 @main() nounwind { 35 | ; box @Boxee in an instance of %Integer 36 | %1 = load i32, i32* @Boxee 37 | %2 = alloca %Integer 38 | call void @Integer_Create(%Integer* %2, i32 %1) 39 | 40 | ; unbox @Boxee from an instance of %Integer 41 | %3 = call i32 @Integer_GetValue(%Integer* %2) 42 | 43 | ret i32 0 44 | } 45 | -------------------------------------------------------------------------------- /object-oriented-constructs/class-equivalence-test.rst: -------------------------------------------------------------------------------- 1 | Class Equivalence Test 2 | ---------------------- 3 | 4 | There are two ways of doing this: 5 | 6 | - If you can guarantee that each class a unique vtable, you can simply 7 | compare the pointers to the vtable. 8 | - If you cannot guarantee that each class has a unique vtable (because 9 | different vtables may have been merged by the linker), you need to 10 | add a unique field to the vtable so that you can compare that 11 | instead. 12 | 13 | The first variant goes roughly as follows (assuming identical strings 14 | aren't merged by the compiler, something that they are most of the 15 | time): 16 | 17 | .. code-block:: cpp 18 | 19 | bool equal = (typeid(first) == typeid(other)); 20 | 21 | As far as I know, RTTI is simply done by adding two fields to the 22 | \_vtable structure: ``parent`` and ``signature``. The former is a 23 | pointer to the vtable of the parent class and the latter is the mangled 24 | (encoded) name of the class. To see if a given class is another class, 25 | you simply compare the ``signature`` fields. To see if a given class is 26 | a derived class of some other class, you simply walk the chain of 27 | ``parent`` fields, while checking if you have found a matching 28 | signature. 29 | -------------------------------------------------------------------------------- /object-oriented-constructs/class-inheritance-test.rst: -------------------------------------------------------------------------------- 1 | Class Inheritance Test 2 | ---------------------- 3 | 4 | A class inheritance test is a question of the form: 5 | *Is class X identical to or derived from class Y?* 6 | 7 | To answer that question, we can use one of two methods: 8 | 9 | - The naive implementation where we search upwards in the chain of 10 | parents. 11 | - The faster implementation where we search a preallocated list of 12 | parents. 13 | 14 | The naive implementation is documented in the first two exception 15 | handling examples as the ``Object_IsA`` function. 16 | -------------------------------------------------------------------------------- /object-oriented-constructs/classes.rst: -------------------------------------------------------------------------------- 1 | Classes 2 | ------- 3 | 4 | A class is nothing more than a structure with an associated set of 5 | functions that take an implicit first parameter, namely a pointer to the 6 | structure. Therefore, it is very trivial to map a class to LLVM IR: 7 | 8 | .. code-block:: cpp 9 | 10 | #include 11 | 12 | class Foo 13 | { 14 | public: 15 | Foo() 16 | { 17 | _length = 0; 18 | } 19 | 20 | size_t GetLength() const 21 | { 22 | return _length; 23 | } 24 | 25 | void SetLength(size_t value) 26 | { 27 | _length = value; 28 | } 29 | 30 | private: 31 | size_t _length; 32 | }; 33 | 34 | We first transform this code into two separate pieces: 35 | 36 | - The structure definition. 37 | - The list of methods, including the constructor. 38 | 39 | .. code-block:: llvm 40 | 41 | ; The structure definition for class Foo. 42 | %Foo = type { i32 } 43 | 44 | ; The default constructor for class Foo. 45 | define void @Foo_Create_Default(%Foo* %this) nounwind { 46 | %1 = getelementptr %Foo, %Foo* %this, i32 0, i32 0 47 | store i32 0, i32* %1 48 | ret void 49 | } 50 | 51 | ; The Foo::GetLength() method. 52 | define i32 @Foo_GetLength(%Foo* %this) nounwind { 53 | %1 = getelementptr %Foo, %Foo* %this, i32 0, i32 0 54 | %2 = load i32, i32* %1 55 | ret i32 %2 56 | } 57 | 58 | ; The Foo::SetLength() method. 59 | define void @Foo_SetLength(%Foo* %this, i32 %value) nounwind { 60 | %1 = getelementptr %Foo, %Foo* %this, i32 0, i32 0 61 | store i32 %value, i32* %1 62 | ret void 63 | } 64 | 65 | Then we make sure that the constructor (``Foo_Create_Default``) is 66 | invoked 67 | 68 | whenever an instance of the structure is created: 69 | 70 | .. code-block:: cpp 71 | 72 | Foo foo; 73 | 74 | .. code-block:: llvm 75 | 76 | 77 | %foo = alloca %Foo 78 | call void @Foo_Create_Default(%Foo* %foo) 79 | -------------------------------------------------------------------------------- /object-oriented-constructs/index.rst: -------------------------------------------------------------------------------- 1 | Object-Oriented Constructs 2 | ========================== 3 | 4 | In this chapter we'll look at various object-oriented constructs and see 5 | how they can be mapped to LLVM IR. 6 | 7 | .. toctree:: 8 | :maxdepth: 1 9 | :caption: Contents: 10 | 11 | classes 12 | virtual-methods 13 | single-inheritance 14 | multiple-inheritance 15 | virtual-inheritance 16 | interfaces 17 | boxing-and-unboxing 18 | class-equivalence-test 19 | class-inheritance-test 20 | the-new-operator 21 | -------------------------------------------------------------------------------- /object-oriented-constructs/interfaces.rst: -------------------------------------------------------------------------------- 1 | Interfaces 2 | ---------- 3 | 4 | An interface is nothing more than a base class with no data members, 5 | where all the methods are pure virtual (i.e. has no body). 6 | 7 | As such, we've already described how to convert an interface to LLVM IR 8 | - it is done precisely the same way that you convert a virtual member 9 | function to LLVM IR. 10 | -------------------------------------------------------------------------------- /object-oriented-constructs/listings/listing_0.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class Foo 4 | { 5 | public: 6 | Foo() 7 | { 8 | _length = 0; 9 | } 10 | 11 | size_t GetLength() const 12 | { 13 | return _length; 14 | } 15 | 16 | void SetLength(size_t value) 17 | { 18 | _length = value; 19 | } 20 | 21 | private: 22 | size_t _length; 23 | }; 24 | -------------------------------------------------------------------------------- /object-oriented-constructs/listings/listing_1.ll: -------------------------------------------------------------------------------- 1 | ; The structure definition for class Foo. 2 | %Foo = type { i32 } 3 | 4 | ; The default constructor for class Foo. 5 | define void @Foo_Create_Default(%Foo* %this) nounwind { 6 | %1 = getelementptr %Foo* %this, i32 0, i32 0 7 | store i32 0, i32* %1 8 | ret void 9 | } 10 | 11 | ; The Foo::GetLength() method. 12 | define i32 @Foo_GetLength(%Foo* %this) nounwind { 13 | %1 = getelementptr %Foo* %this, i32 0, i32 0 14 | %2 = load i32* %this 15 | ret i32 %2 16 | } 17 | 18 | ; The Foo::SetLength() method. 19 | define void @Foo_SetLength(%Foo* %this, i32 %value) nounwind { 20 | %1 = getelementptr %Foo* %this, i32 0, i32 0 21 | store i32 %value, i32* %1 22 | ret void 23 | } 24 | -------------------------------------------------------------------------------- /object-oriented-constructs/listings/listing_10.cpp: -------------------------------------------------------------------------------- 1 | class BaseA 2 | { 3 | public: 4 | int a; 5 | }; 6 | 7 | class BaseB: public BaseA 8 | { 9 | public: 10 | int b; 11 | }; 12 | 13 | class BaseC: public BaseA 14 | { 15 | public: 16 | int c; 17 | }; 18 | 19 | class Derived: 20 | public virtual BaseB, 21 | public virtual BaseC 22 | { 23 | int d; 24 | }; 25 | -------------------------------------------------------------------------------- /object-oriented-constructs/listings/listing_11.cpp: -------------------------------------------------------------------------------- 1 | class Derived 2 | { 3 | public: 4 | int a; 5 | int b; 6 | int c; 7 | int d; 8 | }; 9 | -------------------------------------------------------------------------------- /object-oriented-constructs/listings/listing_11.ll: -------------------------------------------------------------------------------- 1 | @Boxee = global i32 17 2 | 3 | %Integer = type { i32 } 4 | 5 | define void @Integer_Create(%Integer* %this, i32 %value) nounwind { 6 | ; you might set up a vtable and associated virtual methods here 7 | %1 = getelementptr %Integer* %this, i32 0, i32 0 8 | store i32 %value, i32* %1 9 | ret void 10 | } 11 | 12 | define i32 @Integer_GetValue(%Integer* %this) nounwind { 13 | %1 = getelementptr %Integer* %this, i32 0, i32 0 14 | %2 = load i32* %1 15 | ret i32 %2 16 | } 17 | 18 | define i32 @main() nounwind { 19 | ; box @Boxee in an instance of %Integer 20 | %1 = load i32* @Boxee 21 | %2 = alloca %Integer 22 | call void @Integer_Create(%Integer* %2, i32 %1) 23 | 24 | ; unbox @Boxee from an instance of %Integer 25 | %3 = call i32 @Integer_GetValue(%Integer* %2) 26 | 27 | ret i32 0 28 | } 29 | -------------------------------------------------------------------------------- /object-oriented-constructs/listings/listing_12.cpp: -------------------------------------------------------------------------------- 1 | bool equal = (typeid(first) == typeid(other)); 2 | -------------------------------------------------------------------------------- /object-oriented-constructs/listings/listing_12.ll: -------------------------------------------------------------------------------- 1 | @Boxee = global i32 17 2 | 3 | %Integer = type { i32 } 4 | 5 | define void @Integer_Create(%Integer* %this, i32 %value) nounwind { 6 | ; you might set up a vtable and associated virtual methods here 7 | %1 = getelementptr %Integer* %this, i32 0, i32 0 8 | store i32 %value, i32* %1 9 | ret void 10 | } 11 | 12 | define i32 @Integer_GetValue(%Integer* %this) nounwind { 13 | %1 = getelementptr %Integer* %this, i32 0, i32 0 14 | %2 = load i32* %1 15 | ret i32 %2 16 | } 17 | 18 | define i32 @main() nounwind { 19 | ; box @Boxee in an instance of %Integer 20 | %1 = load i32* @Boxee 21 | %2 = alloca %Integer 22 | call void @Integer_Create(%Integer* %2, i32 %1) 23 | 24 | ; unbox @Boxee from an instance of %Integer 25 | %3 = call i32 @Integer_GetValue(%Integer* %2) 26 | 27 | ret i32 0 28 | } 29 | -------------------------------------------------------------------------------- /object-oriented-constructs/listings/listing_13.cpp: -------------------------------------------------------------------------------- 1 | bool equal = (typeid(first) == typeid(other)); 2 | -------------------------------------------------------------------------------- /object-oriented-constructs/listings/listing_13.ll: -------------------------------------------------------------------------------- 1 | declare i8* @malloc(i32) nounwind 2 | 3 | %X = type { i8 } 4 | 5 | define void @X_Create_Default(%X* %this) nounwind { 6 | %1 = getelementptr %X* %this, i32 0, i32 0 7 | store i8 0, i8* %1 8 | ret void 9 | } 10 | 11 | define void @main() nounwind { 12 | %1 = call i8* @malloc(i32 1) 13 | %2 = bitcast i8* %1 to %X* 14 | call void @X_Create_Default(%X* %2) 15 | ret void 16 | } 17 | -------------------------------------------------------------------------------- /object-oriented-constructs/listings/listing_14.ll: -------------------------------------------------------------------------------- 1 | declare i8* @malloc(i32) nounwind 2 | 3 | %X = type { i8 } 4 | 5 | define void @X_Create_Default(%X* %this) nounwind { 6 | %1 = getelementptr %X* %this, i32 0, i32 0 7 | store i8 0, i8* %1 8 | ret void 9 | } 10 | 11 | define void @main() nounwind { 12 | %1 = call i8* @malloc(i32 1) 13 | %2 = bitcast i8* %1 to %X* 14 | call void @X_Create_Default(%X* %2) 15 | ret void 16 | } 17 | -------------------------------------------------------------------------------- /object-oriented-constructs/listings/listing_15.ll: -------------------------------------------------------------------------------- 1 | declare i8* @malloc(i32) nounwind 2 | 3 | %X = type { i32 } 4 | 5 | define void @X_Create_Default(%X* %this) nounwind { 6 | %1 = getelementptr %X* %this, i32 0, i32 0 7 | store i32 0, i32* %1 8 | ret void 9 | } 10 | 11 | define void @main() nounwind { 12 | %n = alloca i32 ; %n = ptr to the number of elements in the array 13 | store i32 100, i32* %n 14 | 15 | %i = alloca i32 ; %i = ptr to the loop index into the array 16 | store i32 0, i32* %i 17 | 18 | %1 = load i32* %n ; %1 = *%n 19 | %2 = mul i32 %1, 4 ; %2 = %1 * sizeof(X) 20 | %3 = call i8* @malloc(i32 %2) ; %3 = malloc(100 * sizeof(X)) 21 | %4 = bitcast i8* %3 to %X* ; %4 = (X*) %3 22 | br label %.loop_head 23 | 24 | .loop_head: ; for (; %i < %n; %i++) 25 | %5 = load i32* %i 26 | %6 = load i32* %n 27 | %7 = icmp slt i32 %5, %6 28 | br i1 %7, label %.loop_body, label %.loop_tail 29 | 30 | .loop_body: 31 | %8 = getelementptr %X* %4, i32 %5 32 | call void @X_Create_Default(%X* %8) 33 | 34 | %9 = add i32 %5, 1 35 | store i32 %9 i32* %i 36 | 37 | br label %.loop_head 38 | 39 | .loop_tail: 40 | ret void 41 | } 42 | -------------------------------------------------------------------------------- /object-oriented-constructs/listings/listing_2.cpp: -------------------------------------------------------------------------------- 1 | Foo foo; 2 | -------------------------------------------------------------------------------- /object-oriented-constructs/listings/listing_3.cpp: -------------------------------------------------------------------------------- 1 | class Foo 2 | { 3 | public: 4 | virtual int GetLengthTimesTwo() const 5 | { 6 | return _length * 2; 7 | } 8 | 9 | void SetLength(size_t value) 10 | { 11 | _length = value; 12 | } 13 | 14 | private: 15 | int _length; 16 | }; 17 | 18 | int main() 19 | { 20 | Foo foo; 21 | foo.SetLength(4); 22 | return foo.GetLengthTimesTwo(); 23 | } 24 | -------------------------------------------------------------------------------- /object-oriented-constructs/listings/listing_3.ll: -------------------------------------------------------------------------------- 1 | 2 | %foo = alloca %Foo 3 | call void @Foo_Create_Default(%Foo* %foo) 4 | -------------------------------------------------------------------------------- /object-oriented-constructs/listings/listing_4.cpp: -------------------------------------------------------------------------------- 1 | class Foo 2 | { 3 | public: 4 | virtual int GetLengthTimesTwo() const 5 | { 6 | return _length * 2; 7 | } 8 | 9 | void SetLength(size_t value) 10 | { 11 | _length = value; 12 | } 13 | 14 | private: 15 | int _length; 16 | }; 17 | 18 | int main() 19 | { 20 | Foo foo; 21 | foo.SetLength(4); 22 | return foo.GetLengthTimesTwo(); 23 | } 24 | -------------------------------------------------------------------------------- /object-oriented-constructs/listings/listing_4.ll: -------------------------------------------------------------------------------- 1 | %Foo_vtable_type = type { i32(%Foo*)* } 2 | 3 | %Foo = type { %Foo_vtable_type*, i32 } 4 | 5 | define i32 @Foo_GetLengthTimesTwo(%Foo* %this) nounwind { 6 | %1 = getelementptr %Foo* %this, i32 0, i32 1 7 | %2 = load i32* %1 8 | %3 = mul i32 %2, 2 9 | ret i32 %3 10 | } 11 | 12 | @Foo_vtable_data = global %Foo_vtable_type { 13 | i32(%Foo*)* @Foo_GetLengthTimesTwo 14 | } 15 | 16 | define void @Foo_Create_Default(%Foo* %this) nounwind { 17 | %1 = getelementptr %Foo* %this, i32 0, i32 0 18 | store %Foo_vtable_type* @Foo_vtable_data, %Foo_vtable_type** %1 19 | %2 = getelementptr %Foo* %this, i32 0, i32 1 20 | store i32 0, i32* %2 21 | ret void 22 | } 23 | 24 | define void @Foo_SetLength(%Foo* %this, i32 %value) nounwind { 25 | %1 = getelementptr %Foo* %this, i32 0, i32 1 26 | store i32 %value, i32* %1 27 | ret void 28 | } 29 | 30 | define i32 @main(i32 %argc, i8** %argv) nounwind { 31 | %foo = alloca %Foo 32 | call void @Foo_Create_Default(%Foo* %foo) 33 | call void @Foo_SetLength(%Foo* %foo, i32 4) 34 | %1 = getelementptr %Foo* %foo, i32 0, i32 0 35 | %2 = load %Foo_vtable_type** %1 36 | %3 = getelementptr %Foo_vtable_type* %2, i32 0, i32 0 37 | %4 = load i32(%Foo*)** %3 38 | %5 = call i32 %4(%Foo* %foo) 39 | ret i32 %5 40 | } 41 | -------------------------------------------------------------------------------- /object-oriented-constructs/listings/listing_5.cpp: -------------------------------------------------------------------------------- 1 | class Base 2 | { 3 | public: 4 | void SetA(int value) 5 | { 6 | _a = value; 7 | } 8 | 9 | private: 10 | int _a; 11 | }; 12 | 13 | class Derived: public Base 14 | { 15 | public: 16 | void SetB(int value) 17 | { 18 | SetA(value); 19 | _b = value; 20 | } 21 | 22 | protected: 23 | int _b; 24 | } 25 | -------------------------------------------------------------------------------- /object-oriented-constructs/listings/listing_5.ll: -------------------------------------------------------------------------------- 1 | %Foo_vtable_type = type { i32(%Foo*)* } 2 | 3 | %Foo = type { %Foo_vtable_type*, i32 } 4 | 5 | define i32 @Foo_GetLengthTimesTwo(%Foo* %this) nounwind { 6 | %1 = getelementptr %Foo* %this, i32 0, i32 1 7 | %2 = load i32* %1 8 | %3 = mul i32 %2, 2 9 | ret i32 %3 10 | } 11 | 12 | @Foo_vtable_data = global %Foo_vtable_type { 13 | i32(%Foo*)* @Foo_GetLengthTimesTwo 14 | } 15 | 16 | define void @Foo_Create_Default(%Foo* %this) nounwind { 17 | %1 = getelementptr %Foo* %this, i32 0, i32 0 18 | store %Foo_vtable_type* @Foo_vtable_data, %Foo_vtable_type** %1 19 | %2 = getelementptr %Foo* %this, i32 0, i32 1 20 | store i32 0, i32* %2 21 | ret void 22 | } 23 | 24 | define void @Foo_SetLength(%Foo* %this, i32 %value) nounwind { 25 | %1 = getelementptr %Foo* %this, i32 0, i32 1 26 | store i32 %value, i32* %1 27 | ret void 28 | } 29 | 30 | define i32 @main(i32 %argc, i8** %argv) nounwind { 31 | %foo = alloca %Foo 32 | call void @Foo_Create_Default(%Foo* %foo) 33 | call void @Foo_SetLength(%Foo* %foo, i32 4) 34 | %1 = getelementptr %Foo* %foo, i32 0, i32 0 35 | %2 = load %Foo_vtable_type** %1 36 | %3 = getelementptr %Foo_vtable_type* %2, i32 0, i32 0 37 | %4 = load i32(%Foo*)** %3 38 | %5 = call i32 %4(%Foo* %foo) 39 | ret i32 %5 40 | } 41 | -------------------------------------------------------------------------------- /object-oriented-constructs/listings/listing_6.cpp: -------------------------------------------------------------------------------- 1 | class Base 2 | { 3 | public: 4 | void SetA(int value) 5 | { 6 | _a = value; 7 | } 8 | 9 | private: 10 | int _a; 11 | }; 12 | 13 | class Derived: public Base 14 | { 15 | public: 16 | void SetB(int value) 17 | { 18 | SetA(value); 19 | _b = value; 20 | } 21 | 22 | protected: 23 | int _b; 24 | } 25 | -------------------------------------------------------------------------------- /object-oriented-constructs/listings/listing_6.ll: -------------------------------------------------------------------------------- 1 | %Base = type { 2 | i32 ; '_a' in class Base 3 | } 4 | 5 | define void @Base_SetA(%Base* %this, i32 %value) nounwind { 6 | %1 = getelementptr %Base* %this, i32 0, i32 0 7 | store i32 %value, i32* %1 8 | ret void 9 | } 10 | 11 | %Derived = type { 12 | i32, ; '_a' from class Base 13 | i32 ; '_b' from class Derived 14 | } 15 | 16 | define void @Derived_SetB(%Derived* %this, i32 %value) nounwind { 17 | %1 = bitcast %Derived* %this to %Base* 18 | call void @Base_SetA(%Base* %1, i32 %value) 19 | %2 = getelementptr %Derived* %this, i32 0, i32 1 20 | store i32 %value, i32* %2 21 | ret void 22 | } 23 | -------------------------------------------------------------------------------- /object-oriented-constructs/listings/listing_7.cpp: -------------------------------------------------------------------------------- 1 | class BaseA 2 | { 3 | public: 4 | void SetA(int value) 5 | { 6 | _a = value; 7 | } 8 | 9 | private: 10 | int _a; 11 | }; 12 | 13 | class BaseB: public BaseA 14 | { 15 | public: 16 | void SetB(int value) 17 | { 18 | SetA(value); 19 | _b = value; 20 | } 21 | 22 | private: 23 | int _b; 24 | }; 25 | 26 | class Derived: 27 | public BaseA, 28 | public BaseB 29 | { 30 | public: 31 | void SetC(int value) 32 | { 33 | SetB(value); 34 | _c = value; 35 | } 36 | 37 | private: 38 | int _c; 39 | }; 40 | -------------------------------------------------------------------------------- /object-oriented-constructs/listings/listing_7.ll: -------------------------------------------------------------------------------- 1 | %Base = type { 2 | i32 ; '_a' in class Base 3 | } 4 | 5 | define void @Base_SetA(%Base* %this, i32 %value) nounwind { 6 | %1 = getelementptr %Base* %this, i32 0, i32 0 7 | store i32 %value, i32* %1 8 | ret void 9 | } 10 | 11 | %Derived = type { 12 | i32, ; '_a' from class Base 13 | i32 ; '_b' from class Derived 14 | } 15 | 16 | define void @Derived_SetB(%Derived* %this, i32 %value) nounwind { 17 | %1 = bitcast %Derived* %this to %Base* 18 | call void @Base_SetA(%Base* %1, i32 %value) 19 | %2 = getelementptr %Derived* %this, i32 0, i32 1 20 | store i32 %value, i32* %2 21 | ret void 22 | } 23 | -------------------------------------------------------------------------------- /object-oriented-constructs/listings/listing_8.cpp: -------------------------------------------------------------------------------- 1 | class BaseA 2 | { 3 | public: 4 | void SetA(int value) 5 | { 6 | _a = value; 7 | } 8 | 9 | private: 10 | int _a; 11 | }; 12 | 13 | class BaseB: public BaseA 14 | { 15 | public: 16 | void SetB(int value) 17 | { 18 | SetA(value); 19 | _b = value; 20 | } 21 | 22 | private: 23 | int _b; 24 | }; 25 | 26 | class Derived: 27 | public BaseA, 28 | public BaseB 29 | { 30 | public: 31 | void SetC(int value) 32 | { 33 | SetB(value); 34 | _c = value; 35 | } 36 | 37 | private: 38 | int _c; 39 | }; 40 | -------------------------------------------------------------------------------- /object-oriented-constructs/listings/listing_8.ll: -------------------------------------------------------------------------------- 1 | %BaseA = type { 2 | i32 ; '_a' from BaseA 3 | } 4 | 5 | define void @BaseA_SetA(%BaseA* %this, i32 %value) nounwind { 6 | %1 = getelementptr %BaseA* %this, i32 0, i32 0 7 | store i32 %value, i32* %1 8 | ret void 9 | } 10 | 11 | %BaseB = type { 12 | i32, ; '_a' from BaseA 13 | i32 ; '_b' from BaseB 14 | } 15 | 16 | define void @BaseB_SetB(%BaseB* %this, i32 %value) nounwind { 17 | %1 = bitcast %BaseB* %this to %BaseA* 18 | call void @BaseA_SetA(%BaseA* %1, i32 %value) 19 | %2 = getelementptr %BaseB* %this, i32 0, i32 1 20 | store i32 %value, i32* %2 21 | ret void 22 | } 23 | 24 | %Derived = type { 25 | i32, ; '_a' from BaseA 26 | i32, ; '_b' from BaseB 27 | i32 ; '_c' from Derived 28 | } 29 | 30 | define void @Derived_SetC(%Derived* %this, i32 %value) nounwind { 31 | %1 = bitcast %Derived* %this to %BaseB* 32 | call void @BaseB_SetB(%BaseB* %1, i32 %value) 33 | %2 = getelementptr %Derived* %this, i32 0, i32 2 34 | store i32 %value, i32* %2 35 | ret void 36 | } 37 | -------------------------------------------------------------------------------- /object-oriented-constructs/listings/listing_9.cpp: -------------------------------------------------------------------------------- 1 | class BaseA 2 | { 3 | public: 4 | int a; 5 | }; 6 | 7 | class BaseB: public BaseA 8 | { 9 | public: 10 | int b; 11 | }; 12 | 13 | class BaseC: public BaseA 14 | { 15 | public: 16 | int c; 17 | }; 18 | 19 | class Derived: 20 | public virtual BaseB, 21 | public virtual BaseC 22 | { 23 | int d; 24 | }; 25 | -------------------------------------------------------------------------------- /object-oriented-constructs/listings/listing_9.ll: -------------------------------------------------------------------------------- 1 | %BaseA = type { 2 | i32 ; '_a' from BaseA 3 | } 4 | 5 | define void @BaseA_SetA(%BaseA* %this, i32 %value) nounwind { 6 | %1 = getelementptr %BaseA* %this, i32 0, i32 0 7 | store i32 %value, i32* %1 8 | ret void 9 | } 10 | 11 | %BaseB = type { 12 | i32, ; '_a' from BaseA 13 | i32 ; '_b' from BaseB 14 | } 15 | 16 | define void @BaseB_SetB(%BaseB* %this, i32 %value) nounwind { 17 | %1 = bitcast %BaseB* %this to %BaseA* 18 | call void @BaseA_SetA(%BaseA* %1, i32 %value) 19 | %2 = getelementptr %BaseB* %this, i32 0, i32 1 20 | store i32 %value, i32* %2 21 | ret void 22 | } 23 | 24 | %Derived = type { 25 | i32, ; '_a' from BaseA 26 | i32, ; '_b' from BaseB 27 | i32 ; '_c' from Derived 28 | } 29 | 30 | define void @Derived_SetC(%Derived* %this, i32 %value) nounwind { 31 | %1 = bitcast %Derived* %this to %BaseB* 32 | call void @BaseB_SetB(%BaseB* %1, i32 %value) 33 | %2 = getelementptr %Derived* %this, i32 0, i32 2 34 | store i32 %value, i32* %2 35 | ret void 36 | } 37 | -------------------------------------------------------------------------------- /object-oriented-constructs/multiple-inheritance.rst: -------------------------------------------------------------------------------- 1 | Multiple Inheritance 2 | -------------------- 3 | 4 | Multiple inheritance is not that difficult, either, it is merely a 5 | question of laying out the multiple inherited "structures" in order 6 | inside each derived class, while taking into consideration the 7 | duplication of data members that are inherited multiple times. 8 | 9 | WARNING: 10 | This chapter is currently utterly bogus because it basically treats 11 | the non-virtual multiple inheritance as it was virtual. If *you* 12 | feel like finishing it up, please feel free to fork and fix. The 13 | problem is that the `SetB()` and `SetC()` setters need to take into 14 | account the offset of each of the *active* data members used in 15 | `BaseB::SetB()` consideration somehow. 16 | 17 | .. code-block:: cpp 18 | 19 | class BaseA 20 | { 21 | public: 22 | void SetA(int value) 23 | { 24 | _a = value; 25 | } 26 | 27 | private: 28 | int _a; 29 | }; 30 | 31 | class BaseB: public BaseA 32 | { 33 | public: 34 | void SetB(int value) 35 | { 36 | SetA(value); 37 | _b = value; 38 | } 39 | 40 | private: 41 | int _b; 42 | }; 43 | 44 | class Derived: 45 | public BaseA, 46 | public BaseB 47 | { 48 | public: 49 | void SetC(int value) 50 | { 51 | SetB(value); 52 | _c = value; 53 | } 54 | 55 | private: 56 | // Derived now has two '_a' members and one '_b' member. 57 | int _c; 58 | }; 59 | 60 | This is equivalent to the following LLVM IR: 61 | 62 | .. code-block:: llvm 63 | 64 | %BaseA = type { 65 | i32 ; '_a' from BaseA 66 | } 67 | 68 | define void @BaseA_SetA(%BaseA* %this, i32 %value) nounwind { 69 | %1 = getelementptr %BaseA, %BaseA* %this, i32 0, i32 0 70 | store i32 %value, i32* %1 71 | ret void 72 | } 73 | 74 | %BaseB = type { 75 | i32, ; '_a' from BaseA 76 | i32 ; '_b' from BaseB 77 | } 78 | 79 | define void @BaseB_SetB(%BaseB* %this, i32 %value) nounwind { 80 | %1 = bitcast %BaseB* %this to %BaseA* 81 | call void @BaseA_SetA(%BaseA* %1, i32 %value) 82 | %2 = getelementptr %BaseB, %BaseB* %this, i32 0, i32 1 83 | store i32 %value, i32* %2 84 | ret void 85 | } 86 | 87 | %Derived = type { 88 | i32, ; '_a' from BaseA 89 | i32, ; '_a' from BaseB 90 | i32, ; '_b' from BaseB 91 | i32 ; '_c' from Derived 92 | } 93 | 94 | define void @Derived_SetC(%Derived* %this, i32 %value) nounwind { 95 | %1 = bitcast %Derived* %this to %BaseB* 96 | call void @BaseB_SetB(%BaseB* %1, i32 %value) 97 | %2 = getelementptr %Derived, %Derived* %this, i32 0, i32 2 98 | store i32 %value, i32* %2 99 | ret void 100 | } 101 | 102 | And the compiler then supplies the needed type casts and pointer 103 | arithmentic whenever ``baseB`` is being referenced as an instance 104 | of ``BaseB``. Please notice that all it takes is a ``bitcast`` from one 105 | class to another as well as an adjustment of the last argument to 106 | ``getelementptr``. 107 | -------------------------------------------------------------------------------- /object-oriented-constructs/single-inheritance.rst: -------------------------------------------------------------------------------- 1 | Single Inheritance 2 | ------------------ 3 | 4 | Single inheritance is very straightforward: Each "structure" (class) is 5 | laid out in memory after one another in declaration order. 6 | 7 | .. code-block:: cpp 8 | 9 | class Base 10 | { 11 | public: 12 | void SetA(int value) 13 | { 14 | _a = value; 15 | } 16 | 17 | private: 18 | int _a; 19 | }; 20 | 21 | class Derived: public Base 22 | { 23 | public: 24 | void SetB(int value) 25 | { 26 | SetA(value); 27 | _b = value; 28 | } 29 | 30 | protected: 31 | int _b; 32 | } 33 | 34 | Here, ``a`` and ``b`` will be laid out to follow one another in memory 35 | so that inheriting from a class is simply a matter of 36 | 37 | declaring a the base class as a first member in the inheriting class: 38 | 39 | .. code-block:: llvm 40 | 41 | %Base = type { 42 | i32 ; '_a' in class Base 43 | } 44 | 45 | define void @Base_SetA(%Base* %this, i32 %value) nounwind { 46 | %1 = getelementptr %Base, %Base* %this, i32 0, i32 0 47 | store i32 %value, i32* %1 48 | ret void 49 | } 50 | 51 | %Derived = type { 52 | i32, ; '_a' from class Base 53 | i32 ; '_b' from class Derived 54 | } 55 | 56 | define void @Derived_SetB(%Derived* %this, i32 %value) nounwind { 57 | %1 = bitcast %Derived* %this to %Base* 58 | call void @Base_SetA(%Base* %1, i32 %value) 59 | %2 = getelementptr %Derived, %Derived* %this, i32 0, i32 1 60 | store i32 %value, i32* %2 61 | ret void 62 | } 63 | 64 | So the base class simply becomes plain members of the type declaration 65 | for the derived class. 66 | 67 | And then the compiler must insert appropriate type casts whenever the 68 | derived class is being referenced as its base class as shown above with 69 | the ``bitcast`` operator. 70 | -------------------------------------------------------------------------------- /object-oriented-constructs/the-new-operator.rst: -------------------------------------------------------------------------------- 1 | The New Operator 2 | ---------------- 3 | 4 | The ``new`` operator is generally nothing more than a type-safe version 5 | of the C ``malloc`` function - in some implementations of C++, they may 6 | even be called interchangeably without causing unseen or unwanted 7 | side-effects. 8 | 9 | The Instance New Operator 10 | ~~~~~~~~~~~~~~~~~~~~~~~~~ 11 | 12 | All calls of the form ``new X`` are mapped into: 13 | 14 | .. code-block:: llvm 15 | 16 | declare i8* @malloc(i32) nounwind 17 | 18 | %X = type { i8 } 19 | 20 | define void @X_Create_Default(%X* %this) nounwind { 21 | %1 = getelementptr %X, %X* %this, i32 0, i32 0 22 | store i8 0, i8* %1 23 | ret void 24 | } 25 | 26 | define void @main() nounwind { 27 | %1 = call i8* @malloc(i32 1) 28 | %2 = bitcast i8* %1 to %X* 29 | call void @X_Create_Default(%X* %2) 30 | ret void 31 | } 32 | 33 | Calls of the form ``new X(Y, Z)`` are the same, except ``Y`` and ``Z`` 34 | are passed into the constructor as arguments. 35 | 36 | The Array New Operator 37 | ~~~~~~~~~~~~~~~~~~~~~~ 38 | 39 | New operations involving arrays are equally simple. The code 40 | ``new X[100]`` is mapped into a loop that initializes each array element 41 | in turn: 42 | 43 | .. code-block:: llvm 44 | 45 | declare i8* @malloc(i32) nounwind 46 | 47 | %X = type { i32 } 48 | 49 | define void @X_Create_Default(%X* %this) nounwind { 50 | %1 = getelementptr %X, %X* %this, i32 0, i32 0 51 | store i32 0, i32* %1 52 | ret void 53 | } 54 | 55 | define void @main() nounwind { 56 | %n = alloca i32 ; %n = ptr to the number of elements in the array 57 | store i32 100, i32* %n 58 | 59 | %i = alloca i32 ; %i = ptr to the loop index into the array 60 | store i32 0, i32* %i 61 | 62 | %1 = load i32, i32* %n ; %1 = *%n 63 | %2 = mul i32 %1, 4 ; %2 = %1 * sizeof(X) 64 | %3 = call i8* @malloc(i32 %2) ; %3 = malloc(100 * sizeof(X)) 65 | %4 = bitcast i8* %3 to %X* ; %4 = (X*) %3 66 | br label %.loop_head 67 | 68 | .loop_head: ; for (; %i < %n; %i++) 69 | %5 = load i32, i32* %i 70 | %6 = load i32, i32* %n 71 | %7 = icmp slt i32 %5, %6 72 | br i1 %7, label %.loop_body, label %.loop_tail 73 | 74 | .loop_body: 75 | %8 = getelementptr %X, %X* %4, i32 %5 76 | call void @X_Create_Default(%X* %8) 77 | 78 | %9 = add i32 %5, 1 79 | store i32 %9, i32* %i 80 | 81 | br label %.loop_head 82 | 83 | .loop_tail: 84 | ret void 85 | } 86 | -------------------------------------------------------------------------------- /object-oriented-constructs/virtual-inheritance.rst: -------------------------------------------------------------------------------- 1 | Virtual Inheritance 2 | ------------------- 3 | 4 | Virtual inheritance is actually quite simple as it dictates that 5 | identical base classes are to be merged into a single occurrence. For 6 | instance, given this: 7 | 8 | .. code-block:: cpp 9 | 10 | class BaseA 11 | { 12 | public: 13 | int a; 14 | }; 15 | 16 | class BaseB: public BaseA 17 | { 18 | public: 19 | int b; 20 | }; 21 | 22 | class BaseC: public BaseA 23 | { 24 | public: 25 | int c; 26 | }; 27 | 28 | class Derived: 29 | public virtual BaseB, 30 | public virtual BaseC 31 | { 32 | int d; 33 | }; 34 | 35 | ``Derived`` will only contain a single instance of ``BaseA`` even if its 36 | inheritance graph dictates that it should have two 37 | 38 | instances. The result looks something like this: 39 | 40 | .. code-block:: cpp 41 | 42 | class Derived 43 | { 44 | public: 45 | int a; 46 | int b; 47 | int c; 48 | int d; 49 | }; 50 | 51 | So the second instance of ``a`` is silently ignored because it would 52 | cause multiple instances of ``BaseA`` to exist in ``Derived``, 53 | 54 | which clearly would cause lots of confusion and ambiguities. 55 | -------------------------------------------------------------------------------- /object-oriented-constructs/virtual-methods.rst: -------------------------------------------------------------------------------- 1 | Virtual Methods 2 | --------------- 3 | 4 | A virtual method is no more than a compiler-controlled function pointer. 5 | Each virtual method is recorded in the ``vtable``, which is a structure 6 | of all the function pointers needed by a given class: 7 | 8 | .. code-block:: cpp 9 | 10 | class Foo 11 | { 12 | public: 13 | virtual int GetLengthTimesTwo() const 14 | { 15 | return _length * 2; 16 | } 17 | 18 | void SetLength(size_t value) 19 | { 20 | _length = value; 21 | } 22 | 23 | private: 24 | int _length; 25 | }; 26 | 27 | int main() 28 | { 29 | Foo foo; 30 | foo.SetLength(4); 31 | return foo.GetLengthTimesTwo(); 32 | } 33 | 34 | This becomes: 35 | 36 | .. code-block:: llvm 37 | 38 | %Foo_vtable_type = type { i32(%Foo*)* } 39 | 40 | %Foo = type { %Foo_vtable_type*, i32 } 41 | 42 | define i32 @Foo_GetLengthTimesTwo(%Foo* %this) nounwind { 43 | %1 = getelementptr %Foo, %Foo* %this, i32 0, i32 1 44 | %2 = load i32, i32* %1 45 | %3 = mul i32 %2, 2 46 | ret i32 %3 47 | } 48 | 49 | @Foo_vtable_data = global %Foo_vtable_type { 50 | i32(%Foo*)* @Foo_GetLengthTimesTwo 51 | } 52 | 53 | define void @Foo_Create_Default(%Foo* %this) nounwind { 54 | %1 = getelementptr %Foo, %Foo* %this, i32 0, i32 0 55 | store %Foo_vtable_type* @Foo_vtable_data, %Foo_vtable_type** %1 56 | %2 = getelementptr %Foo, %Foo* %this, i32 0, i32 1 57 | store i32 0, i32* %2 58 | ret void 59 | } 60 | 61 | define void @Foo_SetLength(%Foo* %this, i32 %value) nounwind { 62 | %1 = getelementptr %Foo, %Foo* %this, i32 0, i32 1 63 | store i32 %value, i32* %1 64 | ret void 65 | } 66 | 67 | define i32 @main(i32 %argc, i8** %argv) nounwind { 68 | %foo = alloca %Foo 69 | call void @Foo_Create_Default(%Foo* %foo) 70 | call void @Foo_SetLength(%Foo* %foo, i32 4) 71 | %1 = getelementptr %Foo, %Foo* %foo, i32 0, i32 0 72 | %2 = load %Foo_vtable_type*, %Foo_vtable_type** %1 73 | %3 = getelementptr %Foo_vtable_type, %Foo_vtable_type* %2, i32 0, i32 0 74 | %4 = load i32(%Foo*)*, i32(%Foo*)** %3 75 | %5 = call i32 %4(%Foo* %foo) 76 | ret i32 %5 77 | } 78 | 79 | Please notice that some C++ compilers store ``_vtable`` at a negative 80 | offset into the structure so that things like 81 | ``memset(this, 0, sizeof(*this))`` work, even though such commands 82 | should always be avoided in an OOP context. 83 | 84 | 85 | Rust Traits and VTables 86 | ~~~~~~~~~~~~~~~~~~~~~~~ 87 | 88 | Rust does have quite a different object model when compared to C++. However, 89 | when it comes to the low-level details of dynamic dispatch, they are remarkably 90 | similar. We'll explore an example from the `rust documentation `_ and what kind of 91 | llvm IR is emitted by the rustc compiler. Both rust and C++ utilizes virtual 92 | method tables for dynamic dispatch. However, in rust there is no such thing as 93 | virtual methods in the high-level language. Instead we can implement traits 94 | for our data types and then implement an interface that accepts all data types 95 | that implement this trait and dynamically dispatch to the right trait 96 | implementation (i.e., this is the ``dyn Trait`` syntax in the example below). 97 | The full example is given here for easy reference: 98 | 99 | .. literalinclude:: listings/rust-traits/test.rs 100 | :language: rust 101 | 102 | Here the compiler must dynamically decide at runtime, which function to 103 | execute. The compiler only knows that the object stored in the components 104 | vector does satisfy the trait Draw. As a side note for those not so familiar 105 | with rust: wrapping the object within a 106 | ``Box`` essentially puts the object on the heap (somewhat akin to a 107 | ``unique_ptr`` in C++) and effectively allows us to put trait objects (i.e., 108 | ``dyn Drawable`` in this example) in a vector. 109 | 110 | 111 | .. code-block:: llvm 112 | 113 | ; test::Screen::run 114 | ; Function Attrs: nonlazybind uwtable 115 | define void @"Screen::run"(%Screen* %self) { 116 | start: 117 | 118 | ;; (omitting the initial prologue and setup code) 119 | ;; this is the start of the for loop in Screen::run calling the next method 120 | ;; on the iterator for the first time and checking whether it is None (or 121 | ;; null in llvm here) 122 | ;; %5 contains the pointer to the first component in the vector here 123 | %6 = icmp eq i64* %5, null 124 | br i1 %6, label %end, label %forloop 125 | 126 | end: ; preds = %forloop, %start 127 | ret void 128 | 129 | forloop: ; preds = %start, %forloop 130 | %7 = phi i64* [ %next_component, %forloop ], [ %5, %start ] 131 | ;; here the boxed pointer is retrieved and dereferenced to retrieve the 132 | ;; vtable pointer 133 | %8 = bitcast i64* %7 to {}** 134 | %self_ptr = load {}*, {}** %8 135 | %9 = getelementptr inbounds i64, i64* %7, i64 1 136 | %vtable_ptr = bitcast i64* %9 to void ({}*)*** 137 | %vtable = load void ({}*)**, void ({}*)*** %vtable_ptr 138 | ;; 3 is the index into the vtable struct, which refers to the draw implementation for this particular struct 139 | %trait_method_ptr = getelementptr inbounds void ({}*)*, void ({}*)** %vtable, i64 3 140 | %trait_method = load void ({}*)*, void ({}*)** %vmethod 141 | ;; indirect call to trait method 142 | call void %trait_method({}* %self_ptr) 143 | 144 | ;; retrieve the next object 145 | %next_component = call i64* @" as core::iter::traits::iterator::Iterator>::next"({ i64*, i64* }* %iter) 146 | %14 = icmp eq i64* %next_component, null 147 | br i1 %14, label %end, label %forloop 148 | } 149 | 150 | 151 | Within the global variables in the llvm module we can see the vtable as shown 152 | here. Both the ``Button`` and the ``SelectBox`` have associated vtables. 153 | 154 | .. code-block:: llvm 155 | 156 | @vtable.screen = private unnamed_addr constant 157 | ;; the Type of the constant vtable structure 158 | { void (%SelectBox*)*, i64, i64, void (%SelectBox*)* } 159 | { 160 | ;; first entry is the function to drop the object 161 | void (%SelectBox*)* @"core::ptr::drop_in_place", ;; destructor 162 | i64 32, ;; size 163 | i64 8, ;; alignment 164 | ;; last in the vtable is the pointer to the SelectBox::draw implementation 165 | void (%SelectBox*)* @"::draw" 166 | } 167 | 168 | ;; the vtable for Button is structured basically the same 169 | @vtable.button = private unnamed_addr constant 170 | { void (%Button*)*, i64, i64, void (%Button*)* } 171 | { 172 | void (%Button*)* @"core::ptr::drop_in_place", 173 | i64 32, i64 8, 174 | void (%Button*)* @"::draw" 175 | } 176 | 177 | The older version of the rust book also features an excellent an concise `description of how vtables in rust work `_. 178 | It seems that newer version follow the same pattern internally, although this 179 | has been removed from the official rust book. 180 | 181 | Finally, `here is a blogpost `_ that explains vtables and dynamic dispatch and 182 | their differences in rust vs C++ in some more detail. 183 | --------------------------------------------------------------------------------