├── .travis.yml ├── CMakeLists.txt ├── LICENSE ├── README.md ├── cmake └── modules │ └── FindLLVM.cmake ├── include └── llvm-abi │ ├── ABI.hpp │ ├── ABITypeInfo.hpp │ ├── ArgInfo.hpp │ ├── ArgumentIRMapping.hpp │ ├── Builder.hpp │ ├── Callee.hpp │ ├── Caller.hpp │ ├── CallingConvention.hpp │ ├── DataSize.hpp │ ├── DefaultABITypeInfo.hpp │ ├── FunctionEncoder.hpp │ ├── FunctionIRMapping.hpp │ ├── FunctionType.hpp │ ├── LLVMUtils.hpp │ ├── Type.hpp │ ├── TypeBuilder.hpp │ ├── TypePromoter.hpp │ ├── TypedValue.hpp │ └── x86 │ ├── ArgClass.hpp │ ├── CPUFeatures.hpp │ ├── CPUKind.hpp │ ├── Classification.hpp │ ├── Classifier.hpp │ ├── Win64ABI.hpp │ ├── X86_32ABI.hpp │ ├── X86_32ABITypeInfo.hpp │ ├── X86_32Classifier.hpp │ ├── X86_64ABI.hpp │ └── X86_64ABITypeInfo.hpp ├── lib ├── ABI.cpp ├── CMakeLists.txt ├── Callee.cpp ├── Caller.cpp ├── DefaultABITypeInfo.cpp ├── FunctionIRMapping.cpp ├── LLVMUtils.cpp ├── Type.cpp ├── TypeBuilder.cpp ├── TypePromoter.cpp └── x86 │ ├── ArgClass.cpp │ ├── CPUFeatures.cpp │ ├── CPUKind.cpp │ ├── Classification.cpp │ ├── Classifier.cpp │ ├── Win64ABI.cpp │ ├── X86_32ABI.cpp │ ├── X86_32ABITypeInfo.cpp │ ├── X86_32Classifier.cpp │ ├── X86_64ABI.cpp │ └── X86_64ABITypeInfo.cpp └── test ├── CCodeGenerator.cpp ├── CCodeGenerator.hpp ├── CMakeLists.txt ├── ParseTest.cpp ├── TestFunctionType.hpp ├── TestSystem.hpp ├── TokenStream.cpp ├── TokenStream.hpp ├── TypeParser.hpp ├── x86_32 ├── CMakeLists.txt ├── Darwin │ ├── CMakeLists.txt │ ├── DarwinReturnStructEmptyArrayFloat.ll │ ├── DarwinReturnStructFloatUnionEmpty.ll │ ├── DarwinReturnStructVector1Double.ll │ ├── DarwinReturnStructVector1LongLong.ll │ ├── DarwinReturnStructVector2Double.ll │ ├── DarwinReturnStructVector2Int.ll │ ├── DarwinReturnStructVector2LongLong.ll │ ├── DarwinReturnStructVector2Short.ll │ ├── DarwinReturnVector1Double.ll │ ├── DarwinReturnVector1LongLong.ll │ ├── DarwinReturnVector2Double.ll │ ├── DarwinReturnVector2Int.ll │ ├── DarwinReturnVector2LongLong.ll │ └── DarwinReturnVector2Short.ll ├── Pass1Float.ll ├── Pass1Int.ll ├── Pass2Floats.ll ├── Pass2Ints.ll ├── Pass6IntsAndChar.ll ├── Pass6IntsAndPtr.ll ├── Pass8FloatsAndLongDouble.ll ├── Pass9Floats.ll ├── PassArrayStructDoubleInt.ll ├── PassArrayStructDoubleIntInt.ll ├── PassArrayStructDoubleIntLong.ll ├── PassCharShortIntLongLongPtr.ll ├── PassIntStructInt.ll ├── PassIntStructShortUintInt.ll ├── PassLongLongArrayAndReturnLongLongArray.ll ├── PassNamedStruct1Int.ll ├── PassNamedUnion1Int.ll ├── PassStruct1Float.ll ├── PassStruct1Int.ll ├── PassStruct2Floats.ll ├── PassStruct2Ints.ll ├── PassStruct3Ints.ll ├── PassStruct4Ints.ll ├── PassStruct5Ints.ll ├── PassStructArray1Char3Chars.ll ├── PassStructArrayVector4FloatsAndReturnStructArrayVector4Floats.ll ├── PassStructDoubleInt.ll ├── PassStructLongDouble.ll ├── PassStructLongDoubleLongDouble.ll ├── PassStructLongPtr.ll ├── PassStructLongPtrAndReturnPtr.ll ├── PassStructVector4FloatsAndReturnStructVector4Floats.ll ├── PassUnionArray5IntsFloat.ll ├── PassUnionDoubleInt.ll ├── PassVector4FloatsAndReturnVector4Floats.ll ├── ReturnChar.ll ├── ReturnDouble.ll ├── ReturnFloat.ll ├── ReturnInt.ll ├── ReturnLongDouble.ll ├── ReturnSChar.ll ├── ReturnShort.ll ├── ReturnStruct1Float.ll ├── ReturnStruct1Int.ll ├── ReturnStruct2Floats.ll ├── ReturnStruct2Ints.ll ├── ReturnStruct2Ptrs.ll ├── ReturnStruct3Ints.ll ├── ReturnStruct4Ints.ll ├── ReturnStruct5Ints.ll ├── ReturnStructEmptyArrayFloat.ll ├── ReturnStructFloatUnionEmpty.ll ├── ReturnStructLongInt.ll ├── ReturnUChar.ll ├── ReturnUShort.ll ├── VarArgsPassIntVACharShortIntFloatDouble.ll ├── VarArgsPassIntVAInt.ll ├── VarArgsPassIntVANone.ll ├── VarArgsPassIntVAUnionLongDoubleCharLong.ll ├── VarArgsPassPtrVAPtrIntDouble.ll └── VarArgsPassPtrVAStructLongFloat.ll └── x86_64 ├── AVXPassVarArgs.ll ├── AVXStructArrayVector8Floats.ll ├── AVXStructVector8Floats.ll ├── AVXVector8Floats.ll ├── CMakeLists.txt ├── NoAVXPassVarArgs.ll ├── NoAVXStructArrayVector8Floats.ll ├── NoAVXStructVector8Floats.ll ├── NoAVXVector8Floats.ll ├── Pass1Float.ll ├── Pass1Int.ll ├── Pass2Floats.ll ├── Pass2Ints.ll ├── Pass6IntsAndChar.ll ├── Pass6IntsAndPtr.ll ├── Pass8FloatsAndLongDouble.ll ├── Pass9Floats.ll ├── PassArrayStructDoubleInt.ll ├── PassArrayStructDoubleIntInt.ll ├── PassArrayStructDoubleIntLong.ll ├── PassCharShortIntLongLongPtr.ll ├── PassIntStructInt.ll ├── PassIntStructShortUintInt.ll ├── PassLongLongArrayAndReturnLongLongArray.ll ├── PassNamedStruct1Int.ll ├── PassNamedStruct2Ints.ll ├── PassNamedStructPtrInt.ll ├── PassNamedUnion1Int.ll ├── PassStruct1Float.ll ├── PassStruct1Int.ll ├── PassStruct2Floats.ll ├── PassStruct2Ints.ll ├── PassStruct3Ints.ll ├── PassStruct4Ints.ll ├── PassStruct5Ints.ll ├── PassStructArray1Char3Chars.ll ├── PassStructArrayVector4FloatsAndReturnStructArrayVector4Floats.ll ├── PassStructDoubleInt.ll ├── PassStructLongDouble.ll ├── PassStructLongDoubleLongDouble.ll ├── PassStructLongPtr.ll ├── PassStructLongPtrAndReturnPtr.ll ├── PassStructVector4FloatsAndReturnStructVector4Floats.ll ├── PassUnionArray5IntsFloat.ll ├── PassUnionDoubleInt.ll ├── PassVector4FloatsAndReturnVector4Floats.ll ├── ReturnChar.ll ├── ReturnDouble.ll ├── ReturnFloat.ll ├── ReturnInt.ll ├── ReturnLongDouble.ll ├── ReturnSChar.ll ├── ReturnShort.ll ├── ReturnStruct1Float.ll ├── ReturnStruct1Int.ll ├── ReturnStruct2Floats.ll ├── ReturnStruct2Ints.ll ├── ReturnStruct2Ptrs.ll ├── ReturnStruct3Ints.ll ├── ReturnStruct4Ints.ll ├── ReturnStruct5Ints.ll ├── ReturnStructEmptyArrayFloat.ll ├── ReturnStructFloatUnionEmpty.ll ├── ReturnStructLongInt.ll ├── ReturnUChar.ll ├── ReturnUShort.ll ├── ReturnUnionLongDoubleInt.ll ├── VarArgsPassIntVACharShortIntFloatDouble.ll ├── VarArgsPassIntVAInt.ll ├── VarArgsPassIntVANone.ll ├── VarArgsPassIntVAUnionLongDoubleCharLong.ll ├── VarArgsPassPtrVAPtrIntDouble.ll └── VarArgsPassPtrVAStructLongFloat.ll /.travis.yml: -------------------------------------------------------------------------------- 1 | # Build matrix / environment variable are explained on: 2 | # http://about.travis-ci.org/docs/user/build-configuration/ 3 | # This file can be validated on: 4 | # http://lint.travis-ci.org/ 5 | 6 | language: cpp 7 | dist: bionic 8 | sudo: required 9 | 10 | compiler: 11 | - gcc 12 | - clang 13 | 14 | before_install: 15 | - sudo apt-get update 16 | 17 | # Ensure add-apt-repository is installed. 18 | - sudo apt-get install software-properties-common 19 | 20 | # LLVM 21 | - sudo sh -c "echo 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-9 main' >> /etc/apt/sources.list" 22 | - wget -O - http://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - 23 | 24 | - sudo add-apt-repository --yes ppa:ubuntu-toolchain-r/test 25 | 26 | install: 27 | # Install package dependencies. 28 | # (Re-run this command a few times to handle handle random failures.) 29 | - 30 | for i in {1..5}; do 31 | if sudo apt-get update && sudo apt-get install -y llvm-$LLVM_VERSION llvm-$LLVM_VERSION-dev clang-$LLVM_VERSION; then 32 | break; 33 | fi; 34 | sleep 1; 35 | done 36 | 37 | # use the previously installed clang version (since installing one tends to remove another). 38 | - 39 | if [[ "${CXX}" == "clang++" ]]; then 40 | export CXX="clang++-$LLVM_VERSION"; 41 | fi 42 | 43 | before_script: 44 | - mkdir build 45 | - cd build 46 | 47 | script: 48 | - cmake -DCMAKE_BUILD_TYPE="$BUILD_TYPE" -DCMAKE_INSTALL_PREFIX=./artifacts/llvm-abi .. 49 | - make && ctest --output-on-failure 50 | - make install 51 | 52 | env: 53 | - BUILD_TYPE=Debug LLVM_VERSION="9" 54 | - BUILD_TYPE=Release LLVM_VERSION="9" 55 | 56 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | llvm-abi - Copyright (c) 2015 Stephen Cross 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | 21 | ============================================================================== 22 | 23 | This software has significant parts based on Clang (frontend for LLVM), for 24 | which the license follows: 25 | 26 | ============================================================================== 27 | LLVM Release License 28 | ============================================================================== 29 | University of Illinois/NCSA 30 | Open Source License 31 | 32 | Copyright (c) 2007-2015 University of Illinois at Urbana-Champaign. 33 | All rights reserved. 34 | 35 | Developed by: 36 | 37 | LLVM Team 38 | 39 | University of Illinois at Urbana-Champaign 40 | 41 | http://llvm.org 42 | 43 | Permission is hereby granted, free of charge, to any person obtaining a copy of 44 | this software and associated documentation files (the "Software"), to deal with 45 | the Software without restriction, including without limitation the rights to 46 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 47 | of the Software, and to permit persons to whom the Software is furnished to do 48 | so, subject to the following conditions: 49 | 50 | * Redistributions of source code must retain the above copyright notice, 51 | this list of conditions and the following disclaimers. 52 | 53 | * Redistributions in binary form must reproduce the above copyright notice, 54 | this list of conditions and the following disclaimers in the 55 | documentation and/or other materials provided with the distribution. 56 | 57 | * Neither the names of the LLVM Team, University of Illinois at 58 | Urbana-Champaign, nor the names of its contributors may be used to 59 | endorse or promote products derived from this Software without specific 60 | prior written permission. 61 | 62 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 63 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 64 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 65 | CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 66 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 67 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE 68 | SOFTWARE. 69 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # llvm-abi 2 | 3 | This is a library for generating LLVM IR that complies with platform ABIs. 4 | 5 | Typically this is useful for frontends generating code that needs to comply with 6 | a target's language-specific ABI, such as a C ABI. There's a generic interface 7 | for an 'ABI' and implementations for each target (e.g. x86, ARM etc.). 8 | 9 | ## Why? 10 | 11 | LLVM IR doesn't currently have any way for representing language type 12 | information, however platform ABIs are typically expressed in terms of source 13 | language types. 14 | 15 | This means backends don't have all the available information for generating 16 | ABI-correct calls/returns so it's up to frontends to emit code that provides the 17 | necessary information to the backend. 18 | 19 | Unfortunately this task is quite involved and target-specific, hence this 20 | library has been created to handle this and abstract away the details. 21 | 22 | ## Who's developing this? 23 | 24 | This is currently being developed by [Stephen Cross](http://scross.co.uk) and 25 | was created due to the need for good ABI support in the 26 | [Loci](http://loci-lang.org) [compiler](https://github.com/scrossuk/locic); 27 | ultimately the aim is that this library is useful to all LLVM frontends that 28 | are interested in ABI compliance. 29 | 30 | It is worth noting that many significant pieces of functionality have been 31 | pulled out of [Clang](http://clang.llvm.org/). 32 | 33 | If you'd like to contribute, that would be awesome! Also any suggestions or 34 | queries are very welcome (raise a GitHub issue). 35 | 36 | Furthermore, it'd be great to add support for languages beyond C. 37 | 38 | ## Current status 39 | 40 | Currently the following ABIs are supported: 41 | 42 | * x86_32 43 | * x86_64 (note: no Win64 support yet) 44 | 45 | Clearly the aim is to also add support for the other LLVM targets by extracting 46 | the necessary parts from Clang. 47 | 48 | In terms of features, there are at least the following gaping holes in the 49 | library: 50 | 51 | * **CPU selection** - There's a lot of functionality in Clang for selecting a 52 | generic CPU (we typically don't select the native CPU 53 | because similar CPUs with the same architecture may not 54 | have the same processor features) and this needs to be 55 | brought into the library. 56 | * **Encoding user-specified alignment for types** 57 | * **Receiving varargs parameters** 58 | * **Marking arguments as already in-memory** - There are excessive loads/stores 59 | being generated due to not 60 | recognising the arguments are 61 | already in stack memory. 62 | * **inalloca support** - There are some aspects of functionality in various 63 | places but it's very incomplete. 64 | 65 | ## Testing 66 | 67 | The approach to testing is currently to create LLVM IR files that specify an 68 | ABI function type (e.g. `int (double, int)`), which generates some code that's 69 | then checked against the file. 70 | 71 | Two functions will be generated: a caller and a callee, both with the 72 | ABI-encoded function signature. The caller function then receives arguments, 73 | decodes them, then immediately re-encodes them and passes them to the callee. 74 | Further it then decodes the return value and then re-encodes it to return. 75 | 76 | This testing strategy makes it fairly simple to check that the ABI 77 | implementation is encoding and decoding arguments as expected. 78 | 79 | If a test fails then Clang is run to see what it outputs. Essentially the aim is 80 | to always produce output that (functionally) matches Clang. 81 | -------------------------------------------------------------------------------- /cmake/modules/FindLLVM.cmake: -------------------------------------------------------------------------------- 1 | # - Find LLVM headers and libraries. 2 | # This module locates LLVM and adapts the llvm-config output for use with 3 | # CMake. 4 | # 5 | # A given list of COMPONENTS is passed to llvm-config. 6 | # 7 | # The following variables are defined: 8 | # LLVM_FOUND - true if LLVM was found 9 | # LLVM_BINARY_DIR - Directory containing LLVM tools binaries. 10 | # LLVM_CXXFLAGS - C++ compiler flags for files that include LLVM headers. 11 | # LLVM_HOST_TARGET - Target triple used to configure LLVM. 12 | # LLVM_INCLUDE_DIRS - Directory containing LLVM include files. 13 | # LLVM_LDFLAGS - Linker flags to add when linking against LLVM 14 | # (includes -LLLVM_LIBRARY_DIRS). 15 | # LLVM_LIBRARIES - Full paths to the library files to link against. 16 | # LLVM_LIBRARY_DIRS - Directory containing LLVM libraries. 17 | # LLVM_ROOT_DIR - The root directory of the LLVM installation. 18 | # llvm-config is searched for in ${LLVM_ROOT_DIR}/bin. 19 | # LLVM_VERSION_MAJOR - Major version of LLVM. 20 | # LLVM_VERSION_MINOR - Minor version of LLVM. 21 | # LLVM_VERSION_STRING - Full LLVM version string (e.g. 2.9). 22 | # 23 | # These tools are also found: 24 | # LLVM_DIS_EXECUTABLE - Path of 'llvm-dis' executable. 25 | # LLVM_LINK_EXECUTABLE - Path of 'llvm-link' executable. 26 | # LLVM_LLC_EXECUTABLE - Path of 'llc' executable. 27 | # LLVM_NM_EXECUTABLE - Path of 'llvm-nm' executable. 28 | # LLVM_OPT_EXECUTABLE - Path of 'opt' executable. 29 | set(llvm_config_names 30 | llvm-config-9 31 | llvm-config 32 | ) 33 | 34 | find_program(LLVM_CONFIG 35 | NAMES ${llvm_config_names} 36 | PATHS ${LLVM_ROOT_DIR}/bin NO_DEFAULT_PATH 37 | DOC "Path to llvm-config tool.") 38 | find_program(LLVM_CONFIG NAMES ${llvm_config_names}) 39 | 40 | if (NOT LLVM_CONFIG) 41 | message(FATAL_ERROR "Could not find llvm-config. Try manually setting LLVM_CONFIG to the llvm-config executable of the installation to use.") 42 | endif() 43 | 44 | macro(llvm_set var flag) 45 | if(LLVM_FIND_QUIETLY) 46 | set(_quiet_arg ERROR_QUIET) 47 | endif() 48 | execute_process( 49 | COMMAND ${LLVM_CONFIG} --${flag} 50 | OUTPUT_VARIABLE LLVM_${var} 51 | OUTPUT_STRIP_TRAILING_WHITESPACE 52 | ${_quiet_arg} 53 | ) 54 | if(${ARGV2}) 55 | file(TO_CMAKE_PATH "${LLVM_${var}}" LLVM_${var}) 56 | endif() 57 | endmacro() 58 | macro(llvm_set_libs var flag) 59 | if(LLVM_FIND_QUIETLY) 60 | set(_quiet_arg ERROR_QUIET) 61 | endif() 62 | execute_process( 63 | COMMAND ${LLVM_CONFIG} --${flag} ${LLVM_FIND_COMPONENTS} 64 | OUTPUT_VARIABLE tmplibs 65 | OUTPUT_STRIP_TRAILING_WHITESPACE 66 | ${_quiet_arg} 67 | ) 68 | file(TO_CMAKE_PATH "${tmplibs}" tmplibs) 69 | string(REGEX MATCHALL "${pattern}[^ ]+" LLVM_${var} ${tmplibs}) 70 | endmacro() 71 | 72 | llvm_set(VERSION_STRING version) 73 | string(REGEX REPLACE "([0-9]+).*" "\\1" LLVM_VERSION_MAJOR "${LLVM_VERSION_STRING}" ) 74 | string(REGEX REPLACE "[0-9]+\\.([0-9]+).*[A-Za-z]*" "\\1" LLVM_VERSION_MINOR "${LLVM_VERSION_STRING}" ) 75 | 76 | llvm_set(CXXFLAGS cxxflags) 77 | 78 | # On CMake builds of LLVM, the output of llvm-config --cxxflags does not 79 | # include -fno-rtti, leading to linker errors. Be sure to add it. 80 | if(NOT ${LLVM_CXXFLAGS} MATCHES "-fno-rtti") 81 | set(LLVM_CXXFLAGS "${LLVM_CXXFLAGS} -fno-rtti") 82 | endif() 83 | 84 | llvm_set(HOST_TARGET host-target) 85 | llvm_set(INCLUDE_DIRS includedir true) 86 | llvm_set(OBJ_ROOT obj-root true) 87 | llvm_set(ROOT_DIR prefix true) 88 | 89 | # Also use LLVM_OBJ_ROOT here to support custom builds of LLVM. 90 | list(APPEND LLVM_INCLUDE_DIRS "${LLVM_OBJ_ROOT}/include") 91 | 92 | llvm_set(LDFLAGS ldflags) 93 | 94 | # System library dependencies (e.g. "-lz") are accessed using the separate 95 | # "--system-libs" flag. 96 | llvm_set(SYSTEM_LIBS system-libs) 97 | string(REPLACE "\n" " " LLVM_LDFLAGS "${LLVM_LDFLAGS} ${LLVM_SYSTEM_LIBS}") 98 | 99 | llvm_set(LIBRARY_DIRS libdir true) 100 | llvm_set_libs(LIBRARIES libs) 101 | 102 | llvm_set(BINARY_DIR bindir true) 103 | 104 | # Use the default CMake facilities for handling QUIET/REQUIRED. 105 | include(FindPackageHandleStandardArgs) 106 | 107 | set(LLVM_BINARIES_LIST "") 108 | 109 | find_program(LLVM_DIS_EXECUTABLE 110 | NAMES llvm-dis 111 | PATHS ${LLVM_BINARY_DIR} 112 | DOC "Path to llvm-dis executable" 113 | NO_DEFAULT_PATH 114 | ) 115 | 116 | list(APPEND LLVM_BINARIES_LIST "${LLVM_DIS_EXECUTABLE}") 117 | 118 | find_program(LLVM_LINK_EXECUTABLE 119 | NAMES llvm-link 120 | PATHS ${LLVM_BINARY_DIR} 121 | DOC "Path to llvm-link executable" 122 | NO_DEFAULT_PATH 123 | ) 124 | 125 | list(APPEND LLVM_BINARIES_LIST "${LLVM_LINK_EXECUTABLE}") 126 | 127 | find_program(LLVM_LLC_EXECUTABLE 128 | NAMES llc 129 | PATHS ${LLVM_BINARY_DIR} 130 | DOC "Path to llc executable" 131 | NO_DEFAULT_PATH 132 | ) 133 | 134 | list(APPEND LLVM_BINARIES_LIST "${LLVM_LLC_EXECUTABLE}") 135 | 136 | find_program(LLVM_NM_EXECUTABLE 137 | NAMES llvm-nm 138 | PATHS ${LLVM_BINARY_DIR} 139 | DOC "Path to llvm-nm executable" 140 | NO_DEFAULT_PATH 141 | ) 142 | 143 | list(APPEND LLVM_BINARIES_LIST "${LLVM_NM_EXECUTABLE}") 144 | 145 | find_program(LLVM_OPT_EXECUTABLE 146 | NAMES opt 147 | PATHS ${LLVM_BINARY_DIR} 148 | DOC "Path to opt executable" 149 | NO_DEFAULT_PATH 150 | ) 151 | 152 | list(APPEND LLVM_BINARIES_LIST "${LLVM_OPT_EXECUTABLE}") 153 | 154 | find_package_handle_standard_args(LLVM 155 | REQUIRED_VARS LLVM_ROOT_DIR LLVM_HOST_TARGET LLVM_BINARIES_LIST 156 | VERSION_VAR LLVM_VERSION_STRING 157 | ) 158 | -------------------------------------------------------------------------------- /include/llvm-abi/ABI.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LLVMABI_ABI_HPP 2 | #define LLVMABI_ABI_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | namespace llvm_abi { 18 | 19 | class ABITypeInfo; 20 | class Builder; 21 | class FunctionEncoder; 22 | class FunctionType; 23 | class StructMember; 24 | class Type; 25 | 26 | /** 27 | * \brief ABI Interface 28 | * 29 | * This interface represents an ABI for a particular 30 | * target and provides access to information related 31 | * to the ABI, such as type sizes/alignments. It also 32 | * provides methods to encode/decode values when making 33 | * function calls. 34 | */ 35 | class ABI { 36 | public: 37 | /** 38 | * \brief Destructor. 39 | */ 40 | virtual ~ABI() { } 41 | 42 | /** 43 | * \brief Get ABI name. 44 | * 45 | * \return ABI name. 46 | */ 47 | virtual std::string name() const = 0; 48 | 49 | /** 50 | * \brief Get ABI type information. 51 | * 52 | * \return ABI type information. 53 | */ 54 | virtual const ABITypeInfo& typeInfo() const = 0; 55 | 56 | /** 57 | * \brief Get the LLVM calling convention for this ABI. 58 | * 59 | * \param The generic ABI calling convention. 60 | * \return The LLVM calling convention ID. 61 | */ 62 | virtual llvm::CallingConv::ID getCallingConvention(CallingConvention callingConvention) const = 0; 63 | 64 | /** 65 | * \brief Get LLVM function type. 66 | * 67 | * This creates an LLVM function type with an ABI-compliant signature. 68 | * 69 | * \param The ABI function type. 70 | * \return The LLVM function type. 71 | */ 72 | virtual llvm::FunctionType* getFunctionType(const FunctionType& functionType) const = 0; 73 | 74 | /** 75 | * \brief Get function attributes for ABI. 76 | * 77 | * This creates a list of attributes as needed by the ABI for a 78 | * function of the given type. Existng attributes should be 79 | * passed to this method since some may need to be disabled 80 | * (e.g. 'readnone' disabled when arguments are passed via 81 | * indirect pointers). 82 | * 83 | * \param functionType The ABI function type. 84 | * \param existingAttributes The existing function attributes. 85 | * \return The set of attributes for the ABI. 86 | */ 87 | virtual llvm::AttributeList getAttributes(const FunctionType& functionType, 88 | llvm::ArrayRef argumentTypes, 89 | llvm::AttributeList existingAttributes = llvm::AttributeList()) const = 0; 90 | 91 | /** 92 | * \brief Create a function call. 93 | * 94 | * Emits a function call, taking the given ABI-independent 95 | * argument values and returning an ABI-independent value. 96 | * 97 | * This method should be given a function that emits the desired 98 | * call instruction, which provides flexibility (e.g. to use 99 | * an invoke instruction rather than call). This function is 100 | * given the ABI-encoded function arguments and should return the 101 | * function call return value (itself also ABI-encoded). 102 | * 103 | * \param builder The builder for emitting instructions. 104 | * \param functionType The ABI function type. 105 | * \param callBuilder A function that should emit the necessary call. 106 | * \param argument The ABI-independent function arguments. 107 | * \return The decoded function return value. 108 | */ 109 | virtual llvm::Value* createCall(Builder& builder, 110 | const FunctionType& functionType, 111 | std::function)> callBuilder, 112 | llvm::ArrayRef arguments) const = 0; 113 | 114 | /** 115 | * \brief Create function encoder. 116 | * 117 | * Creates a 'function encoder' that can be used to obtain the 118 | * ABI-independent arguments as well as return an ABI-independent 119 | * value. 120 | * 121 | * \brief builder The builder for emitting instructions. 122 | * \param functionType The ABI function type. 123 | * \param arguments The ABI-encoded function arguments. 124 | * \return A function encoder instance. 125 | */ 126 | virtual std::unique_ptr createFunctionEncoder(Builder& builder, 127 | const FunctionType& functionType, 128 | llvm::ArrayRef arguments) const = 0; 129 | 130 | }; 131 | 132 | /** 133 | * \brief Create an ABI for the specified target triple. 134 | * 135 | * \param module The LLVM module. 136 | * \param targetTriple the LLVM target triple. 137 | * \return The ABI for the target. 138 | */ 139 | std::unique_ptr createABI(llvm::Module& module, 140 | const llvm::Triple& targetTriple, 141 | const std::string& cpu = ""); 142 | 143 | } 144 | 145 | #endif 146 | -------------------------------------------------------------------------------- /include/llvm-abi/ABITypeInfo.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LLVMABI_ABITYPEINFO_HPP 2 | #define LLVMABI_ABITYPEINFO_HPP 3 | 4 | #include 5 | 6 | // FIXME: Remove! 7 | #include 8 | 9 | namespace llvm_abi { 10 | 11 | class DataSize; 12 | class StructMember; 13 | class Type; 14 | class TypeBuilder; 15 | 16 | /** 17 | * \brief ABI Type Information 18 | */ 19 | class ABITypeInfo { 20 | public: 21 | /** 22 | * \brief Get the type builder being used by this ABI. 23 | * 24 | * \return The type builder being used to create ABI types. 25 | */ 26 | virtual const TypeBuilder& typeBuilder() const = 0; 27 | 28 | /** 29 | * \brief Get the size of a type for this ABI. 30 | * 31 | * \param type The ABI type. 32 | * \return The size of the type. 33 | */ 34 | virtual DataSize getTypeRawSize(Type type) const = 0; 35 | 36 | /** 37 | * \brief Get the allocation size of a type for this ABI. 38 | * 39 | * \param type The ABI type. 40 | * \return The size of the type. 41 | */ 42 | virtual DataSize getTypeAllocSize(Type type) const = 0; 43 | 44 | /** 45 | * \brief Get the store size of a type for this ABI. 46 | * 47 | * \param type The ABI type. 48 | * \return The size of the type. 49 | */ 50 | virtual DataSize getTypeStoreSize(Type type) const = 0; 51 | 52 | /** 53 | * \brief Get the required alignment of a type for this ABI. 54 | * 55 | * \param type The ABI type. 56 | * \return The alignment of the type. 57 | */ 58 | virtual DataSize getTypeRequiredAlign(Type type) const = 0; 59 | 60 | /** 61 | * \brief Get the preferred alignment of a type for this ABI. 62 | * 63 | * \param type The ABI type. 64 | * \return The alignment of the type. 65 | */ 66 | virtual DataSize getTypePreferredAlign(Type type) const = 0; 67 | 68 | /** 69 | * \brief Get the LLVM type used to represent the ABI type given. 70 | * 71 | * \param type The ABI type. 72 | * \return The LLVM type representing the ABI type. 73 | */ 74 | virtual llvm::Type* getLLVMType(Type type) const = 0; 75 | 76 | /** 77 | * \brief Create an array of offsets based on struct member types. 78 | * 79 | * \param structMembers The member types of the struct. 80 | * \return The offsets of each member of the struct. 81 | */ 82 | virtual llvm::SmallVector 83 | calculateStructOffsets(llvm::ArrayRef structMembers) const = 0; 84 | 85 | /** 86 | * \brief Queries whether vector type is legal for target. 87 | * 88 | * \param type The ABI vector type. 89 | * \return Whether the vector type is legal. 90 | */ 91 | virtual bool isLegalVectorType(Type type) const = 0; 92 | 93 | /** 94 | * \brief Queries whether ABI is big-endian. 95 | * 96 | * \return Whether ABI is big-endian. 97 | */ 98 | virtual bool isBigEndian() const = 0; 99 | 100 | /** 101 | * \brief Queries whether 'char' is signed for this ABI. 102 | * 103 | * \return Whether 'char' is signed. 104 | */ 105 | virtual bool isCharSigned() const = 0; 106 | 107 | /** 108 | * \brief Queries if a type can be a homogeneous aggregate base type. 109 | * 110 | * An homogeneous aggregate is a composite type where all of the 111 | * fundamental data types of the members that compose the type 112 | * are the same. 113 | * 114 | * Most ABIs only support float, double, and some vector type 115 | * widths. 116 | * 117 | * \param type The candidate base type. 118 | * \return Whether the specified type can be a base type. 119 | */ 120 | virtual bool isHomogeneousAggregateBaseType(Type type) const = 0; 121 | 122 | /** 123 | * \brief Queries if type is small enough to be a homogeneous aggregate. 124 | * 125 | * An homogeneous aggregate is a composite type where all of the 126 | * fundamental data types of the members that compose the type 127 | * are the same. 128 | * 129 | * \param type The homogeneous aggregate base type. 130 | * \param members The number of members of the homogeneous aggregate. 131 | * \return Whether the homogeneous aggregate is small enough. 132 | */ 133 | virtual bool isHomogeneousAggregateSmallEnough(Type base, 134 | uint64_t members) const = 0; 135 | 136 | protected: 137 | // Prevent destructor call via this class. 138 | ~ABITypeInfo() { } 139 | 140 | }; 141 | 142 | } 143 | 144 | #endif 145 | -------------------------------------------------------------------------------- /include/llvm-abi/ArgumentIRMapping.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LLVMABI_ARGUMENTIRMAPPING_HPP 2 | #define LLVMABI_ARGUMENTIRMAPPING_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace llvm_abi { 9 | 10 | static const size_t InvalidIndex = ~0U; 11 | 12 | /** 13 | * \brief Mapping from ABI argument to IR arguments. 14 | * 15 | * This struct holds the information necessary to translate 16 | * from an ABI argument to an LLVM IR argument. Specifically, 17 | * each ABI argument has: 18 | * 19 | * * An ArgInfo value. 20 | * * A range of IR arguments. 21 | * * A padding IR argument. 22 | * 23 | * The ABI argument is hence expanded to the IR arguments in 24 | * the range [firstArgIndex, firstArgIndex + numberOfIRArgs). 25 | */ 26 | struct ArgumentIRMapping { 27 | size_t paddingArgIndex; 28 | size_t firstArgIndex; 29 | size_t numberOfIRArgs; 30 | 31 | ArgInfo argInfo; 32 | 33 | ArgumentIRMapping() 34 | : paddingArgIndex(InvalidIndex), 35 | firstArgIndex(InvalidIndex), 36 | numberOfIRArgs(0) {} 37 | }; 38 | 39 | } 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /include/llvm-abi/Builder.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LLVMABI_BUILDER_HPP 2 | #define LLVMABI_BUILDER_HPP 3 | 4 | #include 5 | 6 | namespace llvm_abi { 7 | 8 | /** 9 | * \brief LLVM IRBuilder. 10 | */ 11 | typedef llvm::IRBuilder<> IRBuilder; 12 | 13 | /** 14 | * \brief Builder Interface 15 | * 16 | * This is an interface provided by the client to the ABI 17 | * to indicate where instructions should be emitted. 18 | */ 19 | class Builder { 20 | public: 21 | /** 22 | * \brief Get an IRBuilder for the first basic block in the function. 23 | * 24 | * This is used for generating allocas. 25 | * 26 | * \return IRBuilder for the current function's first basic block. 27 | */ 28 | virtual IRBuilder& getEntryBuilder() = 0; 29 | 30 | /** 31 | * \brief Get an IRBuilder for the current position in the function. 32 | * 33 | * \return IRBuilder for the current function's code emitting position. 34 | */ 35 | virtual IRBuilder& getBuilder() = 0; 36 | 37 | protected: 38 | // Prevent destructor calls via this class. 39 | ~Builder() { } 40 | 41 | }; 42 | 43 | } 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /include/llvm-abi/Callee.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LLVMABI_CALLEE_HPP 2 | #define LLVMABI_CALLEE_HPP 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | namespace llvm_abi { 10 | 11 | class ABITypeInfo; 12 | class Builder; 13 | class FunctionIRMapping; 14 | 15 | /** 16 | * \brief Callee 17 | * 18 | * Support class for decoding arguments and encoding return values. 19 | */ 20 | class Callee { 21 | public: 22 | Callee(const ABITypeInfo& typeInfo, 23 | const FunctionType& functionType, 24 | const FunctionIRMapping& functionIRMapping, 25 | Builder& builder); 26 | 27 | /** 28 | * \brief Decode function arguments. 29 | */ 30 | llvm::SmallVector 31 | decodeArguments(llvm::ArrayRef encodedArguments); 32 | 33 | /** 34 | * \brief Encode return value. 35 | */ 36 | llvm::Value* 37 | encodeReturnValue(llvm::Value* returnValue, 38 | llvm::ArrayRef encodedArguments, 39 | llvm::Value* returnValuePtr = nullptr); 40 | 41 | private: 42 | const ABITypeInfo& typeInfo_; 43 | FunctionType functionType_; 44 | const FunctionIRMapping& functionIRMapping_; 45 | Builder& builder_; 46 | 47 | }; 48 | 49 | } 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /include/llvm-abi/Caller.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LLVMABI_CALLER_HPP 2 | #define LLVMABI_CALLER_HPP 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | namespace llvm_abi { 11 | 12 | class ABITypeInfo; 13 | class Builder; 14 | class FunctionIRMapping; 15 | 16 | /** 17 | * \brief Caller 18 | * 19 | * Support class for encoding arguments and decoding return values. 20 | */ 21 | class Caller { 22 | public: 23 | Caller(const ABITypeInfo& typeInfo, 24 | const FunctionType& functionType, 25 | const FunctionIRMapping& functionIRMapping, 26 | Builder& builder); 27 | 28 | /** 29 | * \brief Encode function arguments. 30 | * 31 | * The return value pointer argument allows unnecessary allocas 32 | * to be avoided in some cases (by passing this pointer directly 33 | * as a struct-ret in function calls). 34 | * 35 | * \param arguments Arguments for function call. 36 | * \param returnValuePtr Pointer to return value, if any. 37 | * \return The ABI-encoded arguments. 38 | */ 39 | llvm::SmallVector 40 | encodeArguments(llvm::ArrayRef arguments, 41 | llvm::Value* returnValuePtr = nullptr); 42 | 43 | /** 44 | * \brief Decode return value. 45 | */ 46 | llvm::Value* 47 | decodeReturnValue(llvm::ArrayRef encodedArguments, 48 | llvm::Value* encodedReturnValue, 49 | llvm::Value* returnValuePtr = nullptr); 50 | 51 | private: 52 | const ABITypeInfo& typeInfo_; 53 | FunctionType functionType_; 54 | const FunctionIRMapping& functionIRMapping_; 55 | Builder& builder_; 56 | 57 | }; 58 | 59 | } 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /include/llvm-abi/CallingConvention.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LLVMABI_CALLINGCONVENTION_HPP 2 | #define LLVMABI_CALLINGCONVENTION_HPP 3 | 4 | #include 5 | 6 | namespace llvm_abi { 7 | 8 | /** 9 | * \brief Calling Convention 10 | * 11 | * This enum specifies all possible ABI calling conventions. 12 | */ 13 | enum CallingConvention { 14 | /** 15 | * \brief Default C Calling Convention 16 | */ 17 | CC_CDefault, 18 | 19 | /** 20 | * \brief Default C++ Calling Convention 21 | */ 22 | CC_CppDefault, 23 | 24 | /** 25 | * \brief 'cdecl' calling convention 26 | */ 27 | CC_CDecl, 28 | 29 | /** 30 | * \brief 'stdcall' calling convention 31 | */ 32 | CC_StdCall, 33 | 34 | /** 35 | * \brief 'fastcall' calling convention 36 | */ 37 | CC_FastCall, 38 | 39 | /** 40 | * \brief 'thiscall' calling convention 41 | */ 42 | CC_ThisCall, 43 | 44 | /** 45 | * \brief 'pascal' calling convention 46 | */ 47 | CC_Pascal, 48 | 49 | /** 50 | * \brief MSVC calling convention that passes vectors and 51 | * vector aggregates in SSE registers. 52 | */ 53 | CC_VectorCall 54 | }; 55 | 56 | inline const char* 57 | callingConventionString(const CallingConvention callingConvention) { 58 | switch (callingConvention) { 59 | case CC_CDefault: 60 | return "c-default"; 61 | case CC_CppDefault: 62 | return "c++-default"; 63 | case CC_CDecl: 64 | return "cdecl"; 65 | case CC_StdCall: 66 | return "stdcall"; 67 | case CC_FastCall: 68 | return "fastcall"; 69 | case CC_ThisCall: 70 | return "thiscall"; 71 | case CC_Pascal: 72 | return "pascal"; 73 | case CC_VectorCall: 74 | return "vectorcall"; 75 | } 76 | llvm_unreachable("Unknown calling convention."); 77 | } 78 | 79 | } 80 | 81 | #endif 82 | -------------------------------------------------------------------------------- /include/llvm-abi/DataSize.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LLVMABI_DATASIZE_HPP 2 | #define LLVMABI_DATASIZE_HPP 3 | 4 | #include 5 | 6 | namespace llvm_abi { 7 | 8 | class DataSize { 9 | public: 10 | static DataSize Zero() { 11 | return DataSize(0); 12 | } 13 | 14 | static DataSize Bits(const uint64_t value) { 15 | return DataSize(value); 16 | } 17 | 18 | static DataSize Bytes(const uint64_t value) { 19 | return DataSize(value * 8); 20 | } 21 | 22 | DataSize() = default; 23 | 24 | bool isPowerOf2Bytes() const { 25 | const auto value = asBytes(); 26 | return value != 0 && (value & (value - 1)) == 0; 27 | } 28 | 29 | DataSize roundUpToPowerOf2Bits() const { 30 | auto value = asBits(); 31 | 32 | // Subtract one in case we're already a power of 2. 33 | if (value > 0) { 34 | value--; 35 | } 36 | 37 | // Or together every bit below the highest set bit; we 38 | // can do this a logarithmic number of operations. 39 | value |= value >> 1; 40 | value |= value >> 2; 41 | value |= value >> 4; 42 | value |= value >> 8; 43 | value |= value >> 16; 44 | value |= value >> 32; 45 | 46 | // At this point we have a number like: 47 | // 00001111 48 | // (i.e. some sequence of zeroes followed by some 49 | // sequence of ones). 50 | // So add one and this will get the next power of 2. 51 | value++; 52 | 53 | return DataSize::Bits(value); 54 | } 55 | 56 | DataSize roundUpToPowerOf2Bytes() const { 57 | // Just round up to the next highest number of bytes 58 | // and then any powers of 2 of bits above that will also 59 | // be values in bytes. 60 | return roundUpToAlign(DataSize::Bytes(1)).roundUpToPowerOf2Bits(); 61 | } 62 | 63 | DataSize roundUpToAlign(const DataSize alignment) const { 64 | assert(alignment.isIntegerNumberOfBytes()); 65 | assert(alignment.isPowerOf2Bytes()); 66 | const auto result = DataSize::Bits( 67 | (asBits() + (alignment.asBits() - 1)) & 68 | (~(alignment.asBits() - 1)) 69 | ); 70 | 71 | // If the original value was an integer number of bytes, 72 | // this new value should also be (since the alignment 73 | // must be an integer number of bytes). 74 | assert(!isIntegerNumberOfBytes() || result.isIntegerNumberOfBytes()); 75 | 76 | return result; 77 | } 78 | 79 | bool operator==(const DataSize& other) const { 80 | return asBits() == other.asBits(); 81 | } 82 | 83 | bool operator!=(const DataSize& other) const { 84 | return asBits() != other.asBits(); 85 | } 86 | 87 | bool operator<(const DataSize& other) const { 88 | return asBits() < other.asBits(); 89 | } 90 | 91 | bool operator<=(const DataSize& other) const { 92 | return asBits() <= other.asBits(); 93 | } 94 | 95 | bool operator>(const DataSize& other) const { 96 | return asBits() > other.asBits(); 97 | } 98 | 99 | bool operator>=(const DataSize& other) const { 100 | return asBits() >= other.asBits(); 101 | } 102 | 103 | DataSize operator+(const DataSize& other) const { 104 | return DataSize::Bits(asBits() + other.asBits()); 105 | } 106 | 107 | DataSize operator-(const DataSize& other) const { 108 | assert(*this >= other); 109 | return DataSize::Bits(asBits() - other.asBits()); 110 | } 111 | 112 | DataSize operator*(const uint64_t multiplier) const { 113 | return DataSize::Bits(asBits() * multiplier); 114 | } 115 | 116 | uint64_t operator/(const DataSize& other) const { 117 | return asBits() / other.asBits(); 118 | } 119 | 120 | DataSize& operator+=(const DataSize& other) { 121 | sizeInBits_ += other.asBits(); 122 | return *this; 123 | } 124 | 125 | uint64_t asBits() const { 126 | return sizeInBits_; 127 | } 128 | 129 | bool isIntegerNumberOfBytes() const { 130 | return (asBits() % 8) == 0; 131 | } 132 | 133 | uint64_t asBytes() const { 134 | assert(isIntegerNumberOfBytes()); 135 | return sizeInBits_ / 8; 136 | } 137 | 138 | private: 139 | explicit DataSize(const uint64_t sizeInBits) 140 | : sizeInBits_(sizeInBits) { } 141 | 142 | uint64_t sizeInBits_; 143 | 144 | }; 145 | 146 | } 147 | 148 | #endif 149 | -------------------------------------------------------------------------------- /include/llvm-abi/DefaultABITypeInfo.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LLVMABI_DEFAULTABITYPEINFO_HPP 2 | #define LLVMABI_DEFAULTABITYPEINFO_HPP 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | namespace llvm_abi { 10 | 11 | class DataSize; 12 | class RecordMember; 13 | class Type; 14 | 15 | class DefaultABITypeInfoDelegate { 16 | public: 17 | virtual DataSize getPointerSize() const = 0; 18 | virtual DataSize getPointerAlign() const = 0; 19 | 20 | virtual DataSize getIntSize(IntegerKind kind) const = 0; 21 | virtual DataSize getIntAlign(IntegerKind kind) const = 0; 22 | 23 | virtual DataSize getFloatSize(FloatingPointKind kind) const = 0; 24 | virtual DataSize getFloatAlign(FloatingPointKind kind) const = 0; 25 | 26 | virtual DataSize getComplexSize(FloatingPointKind kind) const = 0; 27 | virtual DataSize getComplexAlign(FloatingPointKind kind) const = 0; 28 | 29 | virtual DataSize getArrayAlign(Type type) const = 0; 30 | virtual DataSize getVectorAlign(Type type) const = 0; 31 | 32 | virtual llvm::Type* getLongDoubleIRType() const = 0; 33 | 34 | protected: 35 | // Prevent destructor call via this class. 36 | ~DefaultABITypeInfoDelegate() { } 37 | 38 | }; 39 | 40 | /** 41 | * \brief Default ABI Type Information 42 | * 43 | * This class contains ABI type information functionality that is 44 | * typically common to all ABIs, such as how to layout structs. 45 | */ 46 | class DefaultABITypeInfo { 47 | public: 48 | DefaultABITypeInfo(llvm::LLVMContext& llvmContext, 49 | const ABITypeInfo& typeInfo, 50 | const DefaultABITypeInfoDelegate& delegate); 51 | ~DefaultABITypeInfo(); 52 | 53 | /** 54 | * \brief Get the size of a type for this ABI. 55 | * 56 | * \param type The ABI type. 57 | * \return The size of the type. 58 | */ 59 | DataSize getDefaultTypeRawSize(Type type) const; 60 | 61 | /** 62 | * \brief Get the allocation size of a type for this ABI. 63 | * 64 | * \param type The ABI type. 65 | * \return The size of the type. 66 | */ 67 | DataSize getDefaultTypeAllocSize(Type type) const; 68 | 69 | /** 70 | * \brief Get the store size of a type for this ABI. 71 | * 72 | * \param type The ABI type. 73 | * \return The size of the type. 74 | */ 75 | DataSize getDefaultTypeStoreSize(Type type) const; 76 | 77 | /** 78 | * \brief Get the required alignment of a type for this ABI. 79 | * 80 | * \param type The ABI type. 81 | * \return The alignment of the type. 82 | */ 83 | DataSize getDefaultTypeRequiredAlign(Type type) const; 84 | 85 | /** 86 | * \brief Get the preferred alignment of a type for this ABI. 87 | * 88 | * \param type The ABI type. 89 | * \return The alignment of the type. 90 | */ 91 | DataSize getDefaultTypePreferredAlign(Type type) const; 92 | 93 | /** 94 | * \brief Get LLVM struct type with name and member types. 95 | * 96 | * \param name The name of the struct (empty string for for literal struct). 97 | * \param members The struct member types. 98 | * \return The LLVM struct type. 99 | */ 100 | llvm::StructType* getLLVMStructType(const std::string& name, 101 | llvm::ArrayRef members) const; 102 | 103 | /** 104 | * \brief Get the LLVM type used to represent the ABI type given. 105 | * 106 | * \param type The ABI type. 107 | * \return The LLVM type representing the ABI type. 108 | */ 109 | llvm::Type* getDefaultLLVMType(Type type) const; 110 | 111 | /** 112 | * \brief Create an array of offsets based on struct member types. 113 | * 114 | * \param structMembers The member types of the struct. 115 | * \return The offsets of each member of the struct. 116 | */ 117 | llvm::SmallVector 118 | calculateDefaultStructOffsets(llvm::ArrayRef structMembers) const; 119 | 120 | private: 121 | llvm::LLVMContext& llvmContext_; 122 | const ABITypeInfo& typeInfo_; 123 | const DefaultABITypeInfoDelegate& delegate_; 124 | mutable std::map structTypes_; 125 | 126 | }; 127 | 128 | } 129 | 130 | #endif 131 | -------------------------------------------------------------------------------- /include/llvm-abi/FunctionEncoder.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LLVMABI_FUNCTIONENCODER_HPP 2 | #define LLVMABI_FUNCTIONENCODER_HPP 3 | 4 | #include 5 | 6 | namespace llvm_abi { 7 | 8 | /** 9 | * \brief Function Encoder 10 | * 11 | * This class represents a function as it is being generated; instances 12 | * of this can be created from an implementation of the 'ABI' interface. 13 | */ 14 | class FunctionEncoder { 15 | public: 16 | /** 17 | * \brief Destructor. 18 | */ 19 | virtual ~FunctionEncoder() { } 20 | 21 | /** 22 | * \brief Get function arguments. 23 | * 24 | * This returns the arguments in ABI-independent form. 25 | * 26 | * \return Decoded function arguments. 27 | */ 28 | virtual llvm::ArrayRef arguments() const = 0; 29 | 30 | /** 31 | * \brief Return a value. 32 | * 33 | * Emits code to return the given value as an encoded return 34 | * value. 35 | * 36 | * \param Return value. 37 | * \return The return instruction emitted. 38 | */ 39 | virtual llvm::ReturnInst* returnValue(llvm::Value* value) = 0; 40 | 41 | /** 42 | * \brief Get return value pointer, if any. 43 | * 44 | * \return Pointer to return value, or NULL if none exists. 45 | */ 46 | virtual llvm::Value* returnValuePointer() const = 0; 47 | 48 | }; 49 | 50 | } 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /include/llvm-abi/FunctionIRMapping.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LLVMABI_FUNCTIONIRMAPPING_HPP 2 | #define LLVMABI_FUNCTIONIRMAPPING_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace llvm_abi { 10 | 11 | /** 12 | * \brief Mapping from ABI function to IR function. 13 | * 14 | * This struct holds the information necessary to translate 15 | * from an ABI function to an LLVM IR function, such as 16 | * the ranges of LLVM IR arguments for each ABI arguments, 17 | * whether there's a struct-return argument etc. 18 | */ 19 | class FunctionIRMapping { 20 | public: 21 | FunctionIRMapping() 22 | : inallocaArgIndex_(InvalidIndex), 23 | structRetArgIndex_(InvalidIndex), 24 | totalIRArgs_(0) { } 25 | 26 | void setReturnArgInfo(const ArgInfo& newReturnArgInfo) { 27 | returnArgInfo_ = newReturnArgInfo; 28 | } 29 | 30 | const ArgInfo& returnArgInfo() const { 31 | return returnArgInfo_; 32 | } 33 | 34 | llvm::ArrayRef arguments() const { 35 | return arguments_; 36 | } 37 | 38 | llvm::SmallVector& arguments() { 39 | return arguments_; 40 | } 41 | 42 | /** 43 | * \brief Query whether function has 'inalloca' argument. 44 | */ 45 | bool hasInallocaArg() const { 46 | return inallocaArgIndex_ != InvalidIndex; 47 | } 48 | 49 | /** 50 | * \brief Get the index of the 'inalloca' argument. 51 | */ 52 | size_t inallocaArgIndex() const { 53 | assert(hasInallocaArg()); 54 | return inallocaArgIndex_; 55 | } 56 | 57 | /** 58 | * \brief Set the index of the 'inalloca' argument. 59 | */ 60 | void setInallocaArgIndex(const size_t argIndex) { 61 | inallocaArgIndex_ = argIndex; 62 | } 63 | 64 | /** 65 | * \brief Query whether function has 'sret' argument. 66 | */ 67 | bool hasStructRetArg() const { 68 | return structRetArgIndex_ != InvalidIndex; 69 | } 70 | 71 | /** 72 | * \brief Get the index of the 'sret' argument. 73 | */ 74 | size_t structRetArgIndex() const { 75 | assert(hasStructRetArg()); 76 | return structRetArgIndex_; 77 | } 78 | 79 | /** 80 | * \brief Set the index of the 'sret' argument. 81 | */ 82 | void setStructRetArgIndex(const size_t argIndex) { 83 | structRetArgIndex_ = argIndex; 84 | } 85 | 86 | /** 87 | * \brief Query whether argument has padding IR argument. 88 | */ 89 | bool hasPaddingArg(const size_t argIndex) const { 90 | assert(argIndex < arguments_.size()); 91 | return arguments_[argIndex].paddingArgIndex != InvalidIndex; 92 | } 93 | 94 | /** 95 | * \brief Get the index of the padding IR argument for 96 | * an ABI argument. 97 | */ 98 | size_t paddingArgIndex(const size_t argIndex) const { 99 | assert(hasPaddingArg(argIndex)); 100 | return arguments_[argIndex].paddingArgIndex; 101 | } 102 | 103 | /** 104 | * \brief Get total number of IR arguments. 105 | */ 106 | size_t totalIRArgs() const { 107 | return totalIRArgs_; 108 | } 109 | 110 | /** 111 | * \brief Set total number of IR arguments. 112 | */ 113 | void setTotalIRArgs(const size_t newTotalIRArgs) { 114 | totalIRArgs_ = newTotalIRArgs; 115 | } 116 | 117 | /** 118 | * \brief Get IR argument range for an ABI argument. 119 | * 120 | * \param Argument index 121 | * \return Pair of index of first IR argument and the 122 | * number of IR arguments. 123 | */ 124 | std::pair 125 | getIRArgRange(const size_t argIndex) const { 126 | assert(argIndex < arguments_.size()); 127 | return std::make_pair(arguments_[argIndex].firstArgIndex, 128 | arguments_[argIndex].numberOfIRArgs); 129 | } 130 | 131 | private: 132 | ArgInfo returnArgInfo_; 133 | size_t inallocaArgIndex_; 134 | size_t structRetArgIndex_; 135 | size_t totalIRArgs_; 136 | llvm::SmallVector arguments_; 137 | 138 | }; 139 | 140 | /** 141 | * \brief Get function IR mapping. 142 | * 143 | * \param argInfoArray The ArgInfo values for each argument. 144 | * \return The mapping from ABI arguments to IR arguments. 145 | */ 146 | FunctionIRMapping 147 | getFunctionIRMapping(const ABITypeInfo& typeInfo, 148 | llvm::ArrayRef argInfoArray); 149 | 150 | /** 151 | * \brief Get LLVM function type. 152 | * 153 | * \param context The LLVM context. 154 | * \param typeInfo The ABI type information. 155 | * \param functionType The ABI function type. 156 | * \param functionIRMapping The ABI function IR mapping. 157 | * \return The ABI-encoded LLVM function type. 158 | */ 159 | llvm::FunctionType * 160 | getFunctionType(llvm::LLVMContext& context, 161 | const ABITypeInfo& typeInfo, 162 | const FunctionType& functionType, 163 | const FunctionIRMapping& functionIRMapping); 164 | 165 | /** 166 | * \brief Get LLVM function attributes. 167 | * 168 | * \param context The LLVM context. 169 | * \param typeInfo The ABI type information. 170 | * \param functionIRMapping The ABI function IR mapping. 171 | * \param existingAttributes Any existing attributes (that may need to 172 | * be removed). 173 | * \return The ABI-encoded LLVM function type. 174 | */ 175 | llvm::AttributeList 176 | getFunctionAttributes(llvm::LLVMContext& llvmContext, 177 | const ABITypeInfo& typeInfo, 178 | const FunctionIRMapping& functionIRMapping, 179 | const llvm::AttributeList existingAttributes); 180 | 181 | } 182 | 183 | #endif 184 | -------------------------------------------------------------------------------- /include/llvm-abi/FunctionType.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LLVMABI_FUNCTIONTYPE_HPP 2 | #define LLVMABI_FUNCTIONTYPE_HPP 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | namespace llvm_abi { 13 | 14 | /** 15 | * \brief Function Type 16 | */ 17 | class FunctionType { 18 | public: 19 | FunctionType(const CallingConvention pCallingConvention, 20 | const Type pReturnType, 21 | llvm::ArrayRef pArgumentTypes, 22 | bool pIsVarArg = false) 23 | : callingConvention_(pCallingConvention), 24 | isVarArg_(pIsVarArg), 25 | returnType_(pReturnType), 26 | argumentTypes_(pArgumentTypes.begin(), pArgumentTypes.end()) { } 27 | 28 | FunctionType(const CallingConvention pCallingConvention, 29 | const Type pReturnType, 30 | std::initializer_list pArgumentTypes, 31 | bool pIsVarArg = false) 32 | : callingConvention_(pCallingConvention), 33 | isVarArg_(pIsVarArg), 34 | returnType_(pReturnType), 35 | argumentTypes_(pArgumentTypes.begin(), pArgumentTypes.end()) { } 36 | 37 | CallingConvention callingConvention() const { 38 | return callingConvention_; 39 | } 40 | 41 | bool isVarArg() const { 42 | return isVarArg_; 43 | } 44 | 45 | Type returnType() const { 46 | return returnType_; 47 | } 48 | 49 | llvm::ArrayRef argumentTypes() const { 50 | return argumentTypes_; 51 | } 52 | 53 | std::string toString() const { 54 | std::string string; 55 | string += "FunctionType(callingConvention: "; 56 | string += callingConventionString(callingConvention()); 57 | string += ", returnType: "; 58 | string += returnType().toString(); 59 | string += ", argumentTypes: ["; 60 | bool first = true; 61 | for (const auto& argType: argumentTypes()) { 62 | if (!first) { 63 | string += ", "; 64 | } else { 65 | first = false; 66 | } 67 | string += argType.toString(); 68 | } 69 | string += "])"; 70 | return string; 71 | } 72 | 73 | private: 74 | CallingConvention callingConvention_; 75 | bool isVarArg_; 76 | Type returnType_; 77 | llvm::SmallVector argumentTypes_; 78 | 79 | }; 80 | 81 | } 82 | 83 | #endif 84 | -------------------------------------------------------------------------------- /include/llvm-abi/LLVMUtils.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LLVMABI_LLVMUTILS_HPP 2 | #define LLVMABI_LLVMUTILS_HPP 3 | 4 | #include 5 | 6 | namespace llvm_abi { 7 | 8 | class ABITypeInfo; 9 | class Builder; 10 | 11 | llvm::AllocaInst* createTempAlloca(const ABITypeInfo& typeInfo, 12 | Builder& builder, 13 | const Type type, 14 | const llvm::Twine& name = ""); 15 | 16 | llvm::AllocaInst* createMemTemp(const ABITypeInfo& typeInfo, 17 | Builder& builder, 18 | const Type type, 19 | const llvm::Twine& name = ""); 20 | 21 | llvm::StoreInst* createStore(llvm::IRBuilder<>& builder, 22 | llvm::Value* const value, 23 | llvm::Value* const ptr); 24 | 25 | llvm::Value* createConstGEP2_32(Builder& builder, 26 | llvm::Type* type, llvm::Value* ptr, 27 | unsigned idx0, unsigned idx1, 28 | const llvm::Twine& name = ""); 29 | 30 | llvm::Value* createStructGEP(Builder& builder, llvm::Type* type, 31 | llvm::Value* ptr, unsigned idx, 32 | const llvm::Twine& name = ""); 33 | 34 | } 35 | 36 | #endif -------------------------------------------------------------------------------- /include/llvm-abi/TypeBuilder.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LLVMABI_TYPEBUILDER_HPP 2 | #define LLVMABI_TYPEBUILDER_HPP 3 | 4 | #include 5 | 6 | #include 7 | 8 | namespace llvm_abi { 9 | 10 | /** 11 | * \brief ABI Type Builder 12 | * 13 | * This class 'uniques' aggregate types so that types can passed around 14 | * with an internal pointer which means that comparison simply involves 15 | * comparing the pointers and copying is just copying the pointers. It 16 | * also has convenience methods for primitive values (e.g. int). 17 | */ 18 | class TypeBuilder { 19 | public: 20 | TypeBuilder(); 21 | 22 | const Type::TypeData* getUniquedTypeData(Type::TypeData typeData) const; 23 | 24 | Type getVoidTy() const; 25 | 26 | Type getPointerTy() const; 27 | 28 | Type getBoolTy() const; 29 | Type getCharTy() const; 30 | Type getShortTy() const; 31 | Type getIntTy() const; 32 | Type getLongTy() const; 33 | Type getLongLongTy() const; 34 | 35 | Type getFloatTy() const; 36 | Type getDoubleTy() const; 37 | Type getLongDoubleTy() const; 38 | Type getFloat128Ty() const; 39 | 40 | Type getStructTy(std::initializer_list memberTypes, 41 | std::string name="") const; 42 | Type getStructTy(llvm::ArrayRef memberTypes, 43 | std::string name="") const; 44 | 45 | Type getUnionTy(std::initializer_list memberTypes, 46 | std::string name="") const; 47 | Type getUnionTy(llvm::ArrayRef memberTypes, 48 | std::string name="") const; 49 | 50 | Type getArrayTy(size_t elementCount, Type elementType) const; 51 | 52 | Type getVectorTy(size_t elementCount, Type elementType) const; 53 | 54 | private: 55 | // Non-copyable. 56 | TypeBuilder(const TypeBuilder&) = delete; 57 | TypeBuilder& operator=(const TypeBuilder&) = delete; 58 | 59 | mutable std::set typeDataSet_; 60 | 61 | }; 62 | 63 | } 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /include/llvm-abi/TypePromoter.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LLVMABI_TYPEPROMOTER_HPP 2 | #define LLVMABI_TYPEPROMOTER_HPP 3 | 4 | #include 5 | 6 | namespace llvm_abi { 7 | 8 | class ABITypeInfo; 9 | class Builder; 10 | class FunctionType; 11 | 12 | /** 13 | * \brief Type Promoter 14 | * 15 | * This class handles promoting types as required in cases such as 16 | * passing varargs arguments. 17 | */ 18 | class TypePromoter { 19 | public: 20 | TypePromoter(const ABITypeInfo& typeInfo); 21 | 22 | TypedValue promoteValue(Builder& builder, 23 | TypedValue value, 24 | Type type) const; 25 | 26 | Type promoteVarArgsArgumentType(Type value) const; 27 | 28 | TypedValue promoteVarArgsArgument(Builder& builder, 29 | TypedValue value) const; 30 | 31 | llvm::SmallVector 32 | promoteArgumentTypes(const FunctionType& functionType, 33 | llvm::ArrayRef argumentTypes) const; 34 | 35 | llvm::SmallVector 36 | promoteArguments(Builder& builder, 37 | const FunctionType& functionType, 38 | llvm::ArrayRef arguments) const; 39 | 40 | private: 41 | const ABITypeInfo& typeInfo_; 42 | 43 | }; 44 | 45 | } 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /include/llvm-abi/TypedValue.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LLVMABI_TYPEDVALUE_HPP 2 | #define LLVMABI_TYPEDVALUE_HPP 3 | 4 | #include 5 | 6 | #include 7 | 8 | namespace llvm_abi { 9 | 10 | class TypedValue { 11 | public: 12 | TypedValue(llvm::Value* const argValue, 13 | const Type argType) 14 | : value_(argValue), 15 | type_(argType) { } 16 | 17 | llvm::Value* llvmValue() const { 18 | return value_; 19 | } 20 | 21 | Type type() const { 22 | return type_; 23 | } 24 | 25 | private: 26 | llvm::Value* value_; 27 | Type type_; 28 | 29 | }; 30 | 31 | } 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /include/llvm-abi/x86/ArgClass.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LLVMABI_X86_64_ARGCLASS_HPP 2 | #define LLVMABI_X86_64_ARGCLASS_HPP 3 | 4 | namespace llvm_abi { 5 | 6 | namespace x86 { 7 | 8 | /** 9 | * \brief x86_64 Argument Class 10 | */ 11 | enum ArgClass { 12 | Integer, 13 | Sse, 14 | SseUp, 15 | X87, 16 | X87Up, 17 | ComplexX87, 18 | NoClass, 19 | Memory 20 | }; 21 | 22 | ArgClass mergeClasses(ArgClass first, ArgClass second); 23 | 24 | } 25 | 26 | } 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /include/llvm-abi/x86/CPUFeatures.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LLVMABI_X86_CPUFEATURES_HPP 2 | #define LLVMABI_X86_CPUFEATURES_HPP 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | 11 | namespace llvm_abi { 12 | 13 | namespace x86 { 14 | 15 | enum SSELevel { 16 | NoSSE, 17 | SSE1, 18 | SSE2, 19 | SSE3, 20 | SSSE3, 21 | SSE41, 22 | SSE42, 23 | AVX, 24 | AVX2, 25 | AVX512F 26 | }; 27 | 28 | class CPUFeatures { 29 | public: 30 | CPUFeatures(); 31 | 32 | void add(const std::string& feature); 33 | 34 | bool hasAVX() const; 35 | 36 | SSELevel sseLevel() const; 37 | 38 | private: 39 | std::set features_; 40 | SSELevel sseLevel_; 41 | 42 | }; 43 | 44 | CPUFeatures getCPUFeatures(const llvm::Triple& targetTriple, 45 | const CPUKind cpu); 46 | 47 | } 48 | 49 | } 50 | 51 | #endif -------------------------------------------------------------------------------- /include/llvm-abi/x86/CPUKind.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LLVMABI_X86_64_CPUKIND_HPP 2 | #define LLVMABI_X86_64_CPUKIND_HPP 3 | 4 | #include 5 | 6 | #include 7 | 8 | namespace llvm_abi { 9 | 10 | namespace x86 { 11 | 12 | /// \brief Enumeration of all of the X86 CPUs supported by Clang. 13 | /// 14 | /// Each enumeration represents a particular CPU supported by Clang. These 15 | /// loosely correspond to the options passed to '-march' or '-mtune' flags. 16 | enum CPUKind { 17 | CK_Generic, 18 | 19 | /// \name i386 20 | /// i386-generation processors. 21 | //@{ 22 | CK_i386, 23 | //@} 24 | 25 | /// \name i486 26 | /// i486-generation processors. 27 | //@{ 28 | CK_i486, 29 | CK_WinChipC6, 30 | CK_WinChip2, 31 | CK_C3, 32 | //@} 33 | 34 | /// \name i586 35 | /// i586-generation processors, P5 microarchitecture based. 36 | //@{ 37 | CK_i586, 38 | CK_Pentium, 39 | CK_PentiumMMX, 40 | //@} 41 | 42 | /// \name i686 43 | /// i686-generation processors, P6 / Pentium M microarchitecture based. 44 | //@{ 45 | CK_i686, 46 | CK_PentiumPro, 47 | CK_Pentium2, 48 | CK_Pentium3, 49 | CK_Pentium3M, 50 | CK_PentiumM, 51 | CK_C3_2, 52 | 53 | /// This enumerator is a bit odd, as GCC no longer accepts -march=yonah. 54 | /// Clang however has some logic to suport this. 55 | // FIXME: Warn, deprecate, and potentially remove this. 56 | CK_Yonah, 57 | //@} 58 | 59 | /// \name Netburst 60 | /// Netburst microarchitecture based processors. 61 | //@{ 62 | CK_Pentium4, 63 | CK_Pentium4M, 64 | CK_Prescott, 65 | CK_Nocona, 66 | //@} 67 | 68 | /// \name Core 69 | /// Core microarchitecture based processors. 70 | //@{ 71 | CK_Core2, 72 | 73 | /// This enumerator, like \see CK_Yonah, is a bit odd. It is another 74 | /// codename which GCC no longer accepts as an option to -march, but Clang 75 | /// has some logic for recognizing it. 76 | // FIXME: Warn, deprecate, and potentially remove this. 77 | CK_Penryn, 78 | //@} 79 | 80 | /// \name Atom 81 | /// Atom processors 82 | //@{ 83 | CK_Bonnell, 84 | CK_Silvermont, 85 | //@} 86 | 87 | /// \name Nehalem 88 | /// Nehalem microarchitecture based processors. 89 | CK_Nehalem, 90 | 91 | /// \name Westmere 92 | /// Westmere microarchitecture based processors. 93 | CK_Westmere, 94 | 95 | /// \name Sandy Bridge 96 | /// Sandy Bridge microarchitecture based processors. 97 | CK_SandyBridge, 98 | 99 | /// \name Ivy Bridge 100 | /// Ivy Bridge microarchitecture based processors. 101 | CK_IvyBridge, 102 | 103 | /// \name Haswell 104 | /// Haswell microarchitecture based processors. 105 | CK_Haswell, 106 | 107 | /// \name Broadwell 108 | /// Broadwell microarchitecture based processors. 109 | CK_Broadwell, 110 | 111 | /// \name Skylake 112 | /// Skylake microarchitecture based processors. 113 | CK_Skylake, 114 | 115 | /// \name Knights Landing 116 | /// Knights Landing processor. 117 | CK_KNL, 118 | 119 | /// \name K6 120 | /// K6 architecture processors. 121 | //@{ 122 | CK_K6, 123 | CK_K6_2, 124 | CK_K6_3, 125 | //@} 126 | 127 | /// \name K7 128 | /// K7 architecture processors. 129 | //@{ 130 | CK_Athlon, 131 | CK_AthlonThunderbird, 132 | CK_Athlon4, 133 | CK_AthlonXP, 134 | CK_AthlonMP, 135 | //@} 136 | 137 | /// \name K8 138 | /// K8 architecture processors. 139 | //@{ 140 | CK_Athlon64, 141 | CK_Athlon64SSE3, 142 | CK_AthlonFX, 143 | CK_K8, 144 | CK_K8SSE3, 145 | CK_Opteron, 146 | CK_OpteronSSE3, 147 | CK_AMDFAM10, 148 | //@} 149 | 150 | /// \name Bobcat 151 | /// Bobcat architecture processors. 152 | //@{ 153 | CK_BTVER1, 154 | CK_BTVER2, 155 | //@} 156 | 157 | /// \name Bulldozer 158 | /// Bulldozer architecture processors. 159 | //@{ 160 | CK_BDVER1, 161 | CK_BDVER2, 162 | CK_BDVER3, 163 | CK_BDVER4, 164 | //@} 165 | 166 | /// This specification is deprecated and will be removed in the future. 167 | /// Users should prefer \see CK_K8. 168 | // FIXME: Warn on this when the CPU is set to it. 169 | //@{ 170 | CK_x86_64, 171 | //@} 172 | 173 | /// \name Geode 174 | /// Geode processors. 175 | //@{ 176 | CK_Geode 177 | //@} 178 | }; 179 | 180 | std::string selectCPUName(const llvm::Triple& /*targetTriple*/, 181 | const std::string& cpu); 182 | 183 | CPUKind getCPUKind(const llvm::Triple& targetTriple, 184 | const std::string& userCPUString); 185 | 186 | } 187 | 188 | } 189 | 190 | #endif -------------------------------------------------------------------------------- /include/llvm-abi/x86/Classification.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LLVMABI_X86_64_CLASSIFICATION_HPP 2 | #define LLVMABI_X86_64_CLASSIFICATION_HPP 3 | 4 | #include 5 | 6 | namespace llvm_abi { 7 | 8 | class ABITypeInfo; 9 | 10 | namespace x86 { 11 | 12 | class Classification { 13 | public: 14 | Classification(); 15 | 16 | ArgClass low() const; 17 | 18 | ArgClass high() const; 19 | 20 | bool isMemory() const; 21 | 22 | void addField(size_t offset, ArgClass fieldClass); 23 | 24 | void classifyType(const ABITypeInfo& typeInfo, 25 | Type type, 26 | size_t offset, 27 | bool isNamedArg); 28 | 29 | private: 30 | // One class for each eightbyte. 31 | ArgClass classes_[2]; 32 | 33 | }; 34 | 35 | } 36 | 37 | } 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /include/llvm-abi/x86/Classifier.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LLVMABI_X86_64_CLASSIFIER_HPP 2 | #define LLVMABI_X86_64_CLASSIFIER_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace llvm_abi { 9 | 10 | namespace x86 { 11 | 12 | class Classification; 13 | 14 | class Classifier { 15 | public: 16 | Classifier(const ABITypeInfo& typeInfo); 17 | 18 | Classification classify(const Type type, 19 | bool isNamedArg); 20 | 21 | ArgInfo classifyType(Type type, 22 | bool isArgument, 23 | unsigned freeIntRegs, 24 | unsigned &neededInt, 25 | unsigned &neededSse, 26 | bool isNamedArg); 27 | 28 | ArgInfo classifyReturnType(Type type); 29 | 30 | llvm::SmallVector 31 | classifyFunctionType(const FunctionType& functionType, 32 | llvm::ArrayRef argumentTypes); 33 | 34 | private: 35 | const ABITypeInfo& typeInfo_; 36 | 37 | }; 38 | 39 | } 40 | 41 | } 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /include/llvm-abi/x86/Win64ABI.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LLVMABI_X86_WIN64ABI_HPP 2 | #define LLVMABI_X86_WIN64ABI_HPP 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | namespace llvm_abi { 17 | 18 | namespace x86 { 19 | 20 | class Win64ABI: public ABI { 21 | public: 22 | Win64ABI(llvm::Module* module); 23 | ~Win64ABI(); 24 | 25 | std::string name() const; 26 | 27 | const ABITypeInfo& typeInfo() const; 28 | 29 | llvm::CallingConv::ID getCallingConvention(CallingConvention callingConvention) const; 30 | 31 | llvm::FunctionType* getFunctionType(const FunctionType& functionType) const; 32 | 33 | llvm::AttributeList getAttributes(const FunctionType& functionType, 34 | llvm::ArrayRef argumentTypes, 35 | llvm::AttributeList existingAttributes) const; 36 | 37 | llvm::Value* createCall(Builder& builder, 38 | const FunctionType& functionType, 39 | std::function)> callBuilder, 40 | llvm::ArrayRef arguments) const; 41 | 42 | std::unique_ptr createFunctionEncoder(Builder& builder, 43 | const FunctionType& functionType, 44 | llvm::ArrayRef arguments) const; 45 | 46 | private: 47 | llvm::LLVMContext& llvmContext_; 48 | 49 | }; 50 | 51 | } 52 | 53 | } 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /include/llvm-abi/x86/X86_32ABI.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LLVMABI_X86_X86_32ABI_HPP 2 | #define LLVMABI_X86_X86_32ABI_HPP 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | namespace llvm_abi { 17 | 18 | namespace x86 { 19 | 20 | class X86_32ABI: public ABI { 21 | public: 22 | X86_32ABI(llvm::Module* module, 23 | llvm::Triple targetTriple); 24 | ~X86_32ABI(); 25 | 26 | std::string name() const; 27 | 28 | const ABITypeInfo& typeInfo() const; 29 | 30 | llvm::CallingConv::ID getCallingConvention(CallingConvention callingConvention) const; 31 | 32 | llvm::FunctionType* getFunctionType(const FunctionType& functionType) const; 33 | 34 | llvm::AttributeList getAttributes(const FunctionType& functionType, 35 | llvm::ArrayRef argumentTypes, 36 | llvm::AttributeList existingAttributes) const; 37 | 38 | llvm::Value* createCall(Builder& builder, 39 | const FunctionType& functionType, 40 | std::function)> callBuilder, 41 | llvm::ArrayRef arguments) const; 42 | 43 | std::unique_ptr 44 | createFunctionEncoder(Builder& builder, 45 | const FunctionType& functionType, 46 | llvm::ArrayRef arguments) const; 47 | 48 | private: 49 | llvm::LLVMContext& llvmContext_; 50 | llvm::Triple targetTriple_; 51 | TypeBuilder typeBuilder_; 52 | X86_32ABITypeInfo typeInfo_; 53 | 54 | }; 55 | 56 | } 57 | 58 | } 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /include/llvm-abi/x86/X86_32ABITypeInfo.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LLVMABI_X86_X86_32ABITYPEINFO_HPP 2 | #define LLVMABI_X86_X86_32ABITYPEINFO_HPP 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace llvm_abi { 13 | 14 | namespace x86 { 15 | 16 | class X86_32ABITypeInfo: public ABITypeInfo, 17 | public DefaultABITypeInfoDelegate { 18 | public: 19 | X86_32ABITypeInfo(llvm::LLVMContext& llvmContext); 20 | 21 | const TypeBuilder& typeBuilder() const; 22 | 23 | DataSize getTypeRawSize(Type type) const; 24 | 25 | DataSize getTypeAllocSize(Type type) const; 26 | 27 | DataSize getTypeStoreSize(Type type) const; 28 | 29 | DataSize getTypeRequiredAlign(Type type) const; 30 | 31 | DataSize getTypePreferredAlign(Type type) const; 32 | 33 | llvm::Type* getLLVMType(Type type) const; 34 | 35 | llvm::SmallVector 36 | calculateStructOffsets(llvm::ArrayRef structMembers) const; 37 | 38 | bool isLegalVectorType(Type type) const; 39 | 40 | bool isBigEndian() const; 41 | 42 | bool isCharSigned() const; 43 | 44 | bool isHomogeneousAggregateBaseType(Type type) const; 45 | 46 | bool isHomogeneousAggregateSmallEnough(Type base, 47 | uint64_t members) const; 48 | 49 | DataSize getPointerSize() const; 50 | DataSize getPointerAlign() const; 51 | 52 | DataSize getIntSize(IntegerKind kind) const; 53 | DataSize getIntAlign(IntegerKind kind) const; 54 | 55 | DataSize getFloatSize(FloatingPointKind kind) const; 56 | DataSize getFloatAlign(FloatingPointKind kind) const; 57 | 58 | DataSize getComplexSize(FloatingPointKind kind) const; 59 | DataSize getComplexAlign(FloatingPointKind kind) const; 60 | 61 | DataSize getArrayAlign(Type type) const; 62 | DataSize getVectorAlign(Type type) const; 63 | 64 | llvm::Type* getLongDoubleIRType() const; 65 | 66 | private: 67 | llvm::LLVMContext& llvmContext_; 68 | TypeBuilder typeBuilder_; 69 | DefaultABITypeInfo defaultABITypeInfo_; 70 | 71 | }; 72 | 73 | } 74 | 75 | } 76 | 77 | #endif 78 | -------------------------------------------------------------------------------- /include/llvm-abi/x86/X86_32Classifier.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LLVMABI_X86_X86_32CLASSIFIER_HPP 2 | #define LLVMABI_X86_X86_32CLASSIFIER_HPP 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace llvm_abi { 13 | 14 | namespace x86 { 15 | 16 | struct CCState { 17 | CCState(const CallingConvention argCallingConvention) : 18 | callingConvention(argCallingConvention), 19 | freeRegs(0), freeSSERegs(0) {} 20 | 21 | CallingConvention callingConvention; 22 | unsigned freeRegs; 23 | unsigned freeSSERegs; 24 | }; 25 | 26 | class X86_32Classifier { 27 | public: 28 | enum Class { 29 | Integer, 30 | Float 31 | }; 32 | 33 | X86_32Classifier(const ABITypeInfo& typeInfo, 34 | const TypeBuilder& typeBuilder, 35 | llvm::Triple targetTriple); 36 | 37 | bool isDarwinVectorABI() const; 38 | bool isSmallStructInRegABI() const; 39 | bool isWin32StructABI() const; 40 | 41 | bool shouldReturnTypeInRegister(Type type) const; 42 | 43 | ArgInfo getIndirectReturnResult(CCState& state) const; 44 | 45 | bool isSSEVectorType(Type type) const; 46 | 47 | bool isRecordWithSSEVectorType(Type type) const; 48 | 49 | DataSize getTypeStackAlignInBytes(Type type, 50 | DataSize align) const; 51 | 52 | ArgInfo getIndirectResult(Type type, 53 | bool isByVal, 54 | CCState& state) const; 55 | 56 | Class classify(Type type) const; 57 | 58 | bool shouldUseInReg(Type type, 59 | CCState& state, 60 | bool& needsPadding) const; 61 | 62 | /// IsX86_MMXType - Return true if this is an MMX type. 63 | bool isX86_MMXType(Type type) const; 64 | 65 | bool is32Or64BitBasicType(Type type) const; 66 | 67 | /// canExpandIndirectArgument - Test whether an argument type which is to be 68 | /// passed indirectly (on the stack) would have the equivalent layout if it was 69 | /// expanded into separate arguments. If so, we prefer to do the latter to avoid 70 | /// inhibiting optimizations. 71 | bool canExpandIndirectArgument(Type type) const; 72 | 73 | ArgInfo classifyReturnType(Type returnType, 74 | CCState& state) const; 75 | 76 | ArgInfo classifyArgumentType(Type type, 77 | CCState& state) const; 78 | 79 | llvm::SmallVector 80 | classifyFunctionType(const FunctionType& functionType, 81 | llvm::ArrayRef argumentTypes) const; 82 | 83 | private: 84 | const ABITypeInfo& typeInfo_; 85 | const TypeBuilder& typeBuilder_; 86 | llvm::Triple targetTriple_; 87 | 88 | }; 89 | 90 | } 91 | 92 | } 93 | 94 | #endif 95 | -------------------------------------------------------------------------------- /include/llvm-abi/x86/X86_64ABI.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LLVMABI_X86_64_X86_64ABI_HPP 2 | #define LLVMABI_X86_64_X86_64ABI_HPP 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | namespace llvm_abi { 21 | 22 | namespace x86 { 23 | 24 | using ABISizeCache = std::unordered_map; 25 | using ABITypeCache = std::unordered_map; 26 | 27 | class X86_64ABI: public ABI { 28 | public: 29 | X86_64ABI(llvm::Module* module, 30 | const llvm::Triple& targetTriple, 31 | const std::string& cpuName); 32 | ~X86_64ABI(); 33 | 34 | llvm::LLVMContext& context() const { 35 | return llvmContext_; 36 | } 37 | 38 | llvm::Value* memcpyIntrinsic() const { 39 | return nullptr; 40 | } 41 | 42 | std::string name() const; 43 | 44 | const ABITypeInfo& typeInfo() const; 45 | 46 | llvm::CallingConv::ID getCallingConvention(CallingConvention callingConvention) const; 47 | 48 | llvm::FunctionType* getFunctionType(const FunctionType& functionType) const; 49 | 50 | llvm::AttributeList getAttributes(const FunctionType& functionType, 51 | llvm::ArrayRef argumentTypes, 52 | llvm::AttributeList existingAttributes) const; 53 | 54 | llvm::Value* createCall(Builder& builder, 55 | const FunctionType& functionType, 56 | std::function)> callBuilder, 57 | llvm::ArrayRef arguments) const; 58 | 59 | std::unique_ptr 60 | createFunctionEncoder(Builder& builder, 61 | const FunctionType& functionType, 62 | llvm::ArrayRef arguments) const; 63 | 64 | private: 65 | llvm::LLVMContext& llvmContext_; 66 | CPUKind cpuKind_; 67 | CPUFeatures cpuFeatures_; 68 | llvm::Module* module_; 69 | X86_64ABITypeInfo typeInfo_; 70 | mutable ABITypeCache abiTypeCache_; 71 | mutable ABISizeCache alignOfCache_; 72 | mutable ABISizeCache sizeOfCache_; 73 | 74 | }; 75 | 76 | } 77 | 78 | } 79 | 80 | #endif 81 | -------------------------------------------------------------------------------- /include/llvm-abi/x86/X86_64ABITypeInfo.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LLVMABI_X86_X86_64ABITYPEINFO_HPP 2 | #define LLVMABI_X86_X86_64ABITYPEINFO_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | namespace llvm_abi { 15 | 16 | namespace x86 { 17 | 18 | class CPUFeatures; 19 | 20 | class X86_64ABITypeInfo: public ABITypeInfo, 21 | public DefaultABITypeInfoDelegate { 22 | public: 23 | X86_64ABITypeInfo(llvm::LLVMContext& llvmContext, 24 | const CPUFeatures& cpuFeatures); 25 | 26 | const TypeBuilder& typeBuilder() const; 27 | 28 | DataSize getTypeRawSize(Type type) const; 29 | 30 | DataSize getTypeAllocSize(Type type) const; 31 | 32 | DataSize getTypeStoreSize(Type type) const; 33 | 34 | DataSize getTypeRequiredAlign(Type type) const; 35 | 36 | DataSize getTypePreferredAlign(Type type) const; 37 | 38 | llvm::Type* getLLVMType(Type type) const; 39 | 40 | llvm::SmallVector 41 | calculateStructOffsets(llvm::ArrayRef structMembers) const; 42 | 43 | bool isLegalVectorType(Type type) const; 44 | 45 | bool isBigEndian() const; 46 | 47 | bool isCharSigned() const; 48 | 49 | bool isHomogeneousAggregateBaseType(Type /*type*/) const { 50 | return false; 51 | } 52 | 53 | bool isHomogeneousAggregateSmallEnough(Type /*base*/, 54 | uint64_t /*members*/) const { 55 | return false; 56 | } 57 | 58 | DataSize getPointerSize() const; 59 | DataSize getPointerAlign() const; 60 | 61 | DataSize getIntSize(IntegerKind kind) const; 62 | DataSize getIntAlign(IntegerKind kind) const; 63 | 64 | DataSize getFloatSize(FloatingPointKind kind) const; 65 | DataSize getFloatAlign(FloatingPointKind kind) const; 66 | 67 | DataSize getComplexSize(FloatingPointKind kind) const; 68 | DataSize getComplexAlign(FloatingPointKind kind) const; 69 | 70 | DataSize getArrayAlign(Type type) const; 71 | DataSize getVectorAlign(Type type) const; 72 | 73 | llvm::Type* getLongDoubleIRType() const; 74 | 75 | private: 76 | llvm::LLVMContext& llvmContext_; 77 | const CPUFeatures& cpuFeatures_; 78 | TypeBuilder typeBuilder_; 79 | DefaultABITypeInfo defaultABITypeInfo_; 80 | }; 81 | 82 | } 83 | 84 | } 85 | 86 | #endif 87 | -------------------------------------------------------------------------------- /lib/ABI.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | namespace llvm_abi { 12 | 13 | std::unique_ptr createABI(llvm::Module& module, 14 | const llvm::Triple& targetTriple, 15 | const std::string& cpuName) { 16 | switch (targetTriple.getArch()) { 17 | case llvm::Triple::x86: 18 | return std::unique_ptr(new x86::X86_32ABI(&module, 19 | targetTriple)); 20 | case llvm::Triple::x86_64: { 21 | if (targetTriple.isOSWindows()) { 22 | return std::unique_ptr(new x86::Win64ABI(&module)); 23 | } else { 24 | return std::unique_ptr(new x86::X86_64ABI(&module, 25 | targetTriple, 26 | cpuName)); 27 | } 28 | } 29 | default: 30 | break; 31 | } 32 | 33 | std::string errorString = "No ABI available for triple: "; 34 | errorString += targetTriple.str(); 35 | throw std::runtime_error(errorString); 36 | } 37 | 38 | } 39 | 40 | -------------------------------------------------------------------------------- /lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(llvm-abi 2 | ABI.cpp 3 | Callee.cpp 4 | Caller.cpp 5 | DefaultABITypeInfo.cpp 6 | FunctionIRMapping.cpp 7 | LLVMUtils.cpp 8 | Type.cpp 9 | TypeBuilder.cpp 10 | TypePromoter.cpp 11 | x86/ArgClass.cpp 12 | x86/Classification.cpp 13 | x86/Classifier.cpp 14 | x86/CPUFeatures.cpp 15 | x86/CPUKind.cpp 16 | x86/Win64ABI.cpp 17 | x86/X86_32ABI.cpp 18 | x86/X86_32ABITypeInfo.cpp 19 | x86/X86_32Classifier.cpp 20 | x86/X86_64ABI.cpp 21 | x86/X86_64ABITypeInfo.cpp 22 | ) 23 | 24 | install(TARGETS llvm-abi 25 | ARCHIVE DESTINATION "lib" 26 | ) 27 | -------------------------------------------------------------------------------- /lib/LLVMUtils.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | namespace llvm_abi { 6 | 7 | llvm::AllocaInst* createTempAlloca(const ABITypeInfo& typeInfo, 8 | Builder& builder, 9 | const Type type, 10 | const llvm::Twine& name) { 11 | const auto allocaInst = builder.getEntryBuilder().CreateAlloca(typeInfo.getLLVMType(type)); 12 | allocaInst->setName(name); 13 | return allocaInst; 14 | } 15 | 16 | llvm::AllocaInst* createMemTemp(const ABITypeInfo& typeInfo, 17 | Builder& builder, 18 | const Type type, 19 | const llvm::Twine& name) { 20 | const auto allocaInst = createTempAlloca(typeInfo, 21 | builder, 22 | type, 23 | name); 24 | allocaInst->setAlignment(typeInfo.getTypeRequiredAlign(type).asBytes()); 25 | return allocaInst; 26 | } 27 | 28 | llvm::StoreInst* createStore(llvm::IRBuilder<>& builder, 29 | llvm::Value* const value, 30 | llvm::Value* const ptr) { 31 | assert(ptr->getType()->isPointerTy()); 32 | const auto castPtr = builder.CreatePointerCast(ptr, 33 | value->getType()->getPointerTo()); 34 | return builder.CreateStore(value, castPtr); 35 | } 36 | 37 | llvm::Value* createConstGEP2_32(Builder& builder, 38 | llvm::Type* type, llvm::Value* ptr, 39 | unsigned idx0, unsigned idx1, 40 | const llvm::Twine& name) { 41 | assert(ptr->getType()->isPointerTy()); 42 | return builder.getBuilder().CreateConstGEP2_32(type, ptr, idx0, 43 | idx1, name); 44 | } 45 | 46 | llvm::Value* createStructGEP(Builder& builder, llvm::Type* type, 47 | llvm::Value* ptr, unsigned idx, 48 | const llvm::Twine& name) { 49 | assert(ptr->getType()->isPointerTy()); 50 | return builder.getBuilder().CreateStructGEP(type, ptr, idx, 51 | name); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /lib/TypeBuilder.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace llvm_abi { 7 | 8 | TypeBuilder::TypeBuilder() { } 9 | 10 | const Type::TypeData* TypeBuilder::getUniquedTypeData(Type::TypeData typeData) const { 11 | auto result = typeDataSet_.insert(std::move(typeData)); 12 | return &(*(result.first)); 13 | } 14 | 15 | Type TypeBuilder::getVoidTy() const { 16 | return VoidTy; 17 | } 18 | 19 | Type TypeBuilder::getPointerTy() const { 20 | return PointerTy; 21 | } 22 | 23 | Type TypeBuilder::getBoolTy() const { 24 | return BoolTy; 25 | } 26 | 27 | Type TypeBuilder::getCharTy() const { 28 | return CharTy; 29 | } 30 | 31 | Type TypeBuilder::getShortTy() const { 32 | return ShortTy; 33 | } 34 | 35 | Type TypeBuilder::getIntTy() const { 36 | return IntTy; 37 | } 38 | 39 | Type TypeBuilder::getLongTy() const { 40 | return LongTy; 41 | } 42 | 43 | Type TypeBuilder::getLongLongTy() const { 44 | return LongLongTy; 45 | } 46 | 47 | Type TypeBuilder::getFloatTy() const { 48 | return FloatTy; 49 | } 50 | 51 | Type TypeBuilder::getDoubleTy() const { 52 | return DoubleTy; 53 | } 54 | 55 | Type TypeBuilder::getLongDoubleTy() const { 56 | return LongDoubleTy; 57 | } 58 | 59 | Type TypeBuilder::getFloat128Ty() const { 60 | return Float128Ty; 61 | } 62 | 63 | Type TypeBuilder::getStructTy(std::initializer_list memberTypes, 64 | std::string name) const { 65 | return Type::AutoStruct(*this, 66 | llvm::ArrayRef(memberTypes.begin(), 67 | memberTypes.end()), 68 | std::move(name)); 69 | } 70 | 71 | Type TypeBuilder::getUnionTy(llvm::ArrayRef memberTypes, 72 | std::string name) const { 73 | return Type::Union(*this, memberTypes, std::move(name)); 74 | } 75 | 76 | Type TypeBuilder::getUnionTy(std::initializer_list memberTypes, 77 | std::string name) const { 78 | return Type::Union(*this, 79 | llvm::ArrayRef(memberTypes.begin(), 80 | memberTypes.end()), 81 | std::move(name)); 82 | } 83 | 84 | Type TypeBuilder::getStructTy(llvm::ArrayRef memberTypes, 85 | std::string name) const { 86 | return Type::AutoStruct(*this, memberTypes, std::move(name)); 87 | } 88 | 89 | Type TypeBuilder::getArrayTy(const size_t elementCount, 90 | const Type elementType) const { 91 | return Type::Array(*this, elementCount, elementType); 92 | } 93 | 94 | Type TypeBuilder::getVectorTy(const size_t elementCount, 95 | const Type elementType) const { 96 | return Type::Vector(*this, elementCount, elementType); 97 | } 98 | 99 | } 100 | 101 | -------------------------------------------------------------------------------- /lib/TypePromoter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace llvm_abi { 9 | 10 | TypePromoter::TypePromoter(const ABITypeInfo& typeInfo) 11 | : typeInfo_(typeInfo) { } 12 | 13 | TypedValue TypePromoter::promoteValue(Builder& builder, 14 | const TypedValue value, 15 | const Type type) const { 16 | if (value.type() == type) { 17 | // Nothing to do. 18 | return value; 19 | } 20 | 21 | assert(type.isInteger() || type.isFloatingPoint()); 22 | if (type.isInteger()) { 23 | if (type.hasSignedIntegerRepresentation(typeInfo_)) { 24 | const auto extValue = builder.getBuilder().CreateSExt(value.llvmValue(), 25 | typeInfo_.getLLVMType(type)); 26 | return TypedValue(extValue, type); 27 | } else { 28 | const auto extValue = builder.getBuilder().CreateZExt(value.llvmValue(), 29 | typeInfo_.getLLVMType(type)); 30 | return TypedValue(extValue, type); 31 | } 32 | } else { 33 | const auto extValue = builder.getBuilder().CreateFPExt(value.llvmValue(), 34 | typeInfo_.getLLVMType(type)); 35 | return TypedValue(extValue, type); 36 | } 37 | } 38 | 39 | Type TypePromoter::promoteVarArgsArgumentType(const Type type) const { 40 | if (type.isUnspecifiedWidthInteger()) { 41 | switch (type.integerKind()) { 42 | case Char: 43 | return typeInfo_.isCharSigned() ? 44 | IntTy : UIntTy; 45 | case Bool: 46 | case SChar: 47 | case Short: 48 | return IntTy; 49 | case UChar: 50 | case UShort: 51 | return UIntTy; 52 | case Int: 53 | case Long: 54 | case LongLong: 55 | case SSizeT: 56 | case IntPtrT: 57 | case UInt: 58 | case ULong: 59 | case ULongLong: 60 | case SizeT: 61 | case PtrDiffT: 62 | case UIntPtrT: 63 | return type; 64 | } 65 | llvm_unreachable("Unknown integer type kind."); 66 | } else if (type.isFloatingPoint()) { 67 | switch (type.floatingPointKind()) { 68 | case HalfFloat: 69 | llvm_unreachable("TODO"); 70 | case Float: 71 | return DoubleTy; 72 | case Double: 73 | case LongDouble: 74 | case Float128: 75 | return type; 76 | } 77 | llvm_unreachable("Unknown floating point type kind."); 78 | } else { 79 | return type; 80 | } 81 | } 82 | 83 | TypedValue TypePromoter::promoteVarArgsArgument(Builder& builder, 84 | const TypedValue typedValue) const { 85 | const auto type = typedValue.type(); 86 | return promoteValue(builder, 87 | typedValue, 88 | promoteVarArgsArgumentType(type)); 89 | } 90 | 91 | llvm::SmallVector 92 | TypePromoter::promoteArgumentTypes(const FunctionType& functionType, 93 | llvm::ArrayRef argumentTypes) const { 94 | llvm::SmallVector promotedArgumentTypes; 95 | promotedArgumentTypes.reserve(argumentTypes.size()); 96 | 97 | for (size_t i = 0; i < argumentTypes.size(); i++) { 98 | const bool isVarArgArgument = (i >= functionType.argumentTypes().size()); 99 | if (isVarArgArgument) { 100 | promotedArgumentTypes.push_back(promoteVarArgsArgumentType(argumentTypes[i])); 101 | } else { 102 | // Nothing to do. 103 | promotedArgumentTypes.push_back(argumentTypes[i]); 104 | } 105 | } 106 | 107 | return promotedArgumentTypes; 108 | } 109 | 110 | llvm::SmallVector 111 | TypePromoter::promoteArguments(Builder& builder, 112 | const FunctionType& functionType, 113 | llvm::ArrayRef arguments) const { 114 | llvm::SmallVector promotedArguments; 115 | promotedArguments.reserve(arguments.size()); 116 | 117 | for (size_t i = 0; i < arguments.size(); i++) { 118 | const bool isVarArgArgument = (i >= functionType.argumentTypes().size()); 119 | if (isVarArgArgument) { 120 | promotedArguments.push_back(promoteVarArgsArgument(builder, 121 | arguments[i])); 122 | } else { 123 | // Nothing to do. 124 | promotedArguments.push_back(arguments[i]); 125 | } 126 | } 127 | 128 | return promotedArguments; 129 | } 130 | 131 | } 132 | -------------------------------------------------------------------------------- /lib/x86/ArgClass.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace llvm_abi { 4 | 5 | namespace x86 { 6 | 7 | // Class merge operation as specified in ABI. 8 | ArgClass mergeClasses(const ArgClass first, 9 | const ArgClass second) { 10 | // AMD64-ABI 3.2.3p2: Rule 4. Each field of an object is 11 | // classified recursively so that always two fields are 12 | // considered. The resulting class is calculated according to 13 | // the classes of the fields in the eightbyte: 14 | 15 | // (a) If both classes are equal, this is the resulting class. 16 | if (first == second) { 17 | return first; 18 | } 19 | 20 | // (b) If one of the classes is NO_CLASS, the resulting class is 21 | // the other class. 22 | if (first == NoClass) { 23 | return second; 24 | } 25 | 26 | if (second == NoClass) { 27 | return first; 28 | } 29 | 30 | // (c) If one of the classes is MEMORY, the result is the MEMORY 31 | // class. 32 | if (first == Memory || second == Memory) { 33 | return Memory; 34 | } 35 | 36 | // (d) If one of the classes is INTEGER, the result is the 37 | // INTEGER. 38 | if (first == Integer || second == Integer) { 39 | return Integer; 40 | } 41 | 42 | // (e) If one of the classes is X87, X87UP, COMPLEX_X87 class, 43 | // MEMORY is used as class. 44 | if (first == X87 || first == X87Up || first == ComplexX87 || 45 | second == X87 || second == X87Up || second == ComplexX87) { 46 | return Memory; 47 | } 48 | 49 | // (f) Otherwise class SSE is used. 50 | return Sse; 51 | } 52 | 53 | } 54 | 55 | } 56 | 57 | -------------------------------------------------------------------------------- /lib/x86/CPUKind.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | namespace llvm_abi { 9 | 10 | namespace x86 { 11 | 12 | std::string selectCPUName(const llvm::Triple& /*targetTriple*/, 13 | const std::string& cpu) { 14 | // TODO! 15 | return !cpu.empty() ? cpu : "x86-64"; 16 | } 17 | 18 | CPUKind getCPUKind(const llvm::Triple& targetTriple, 19 | const std::string& userCPUString) { 20 | const auto cpuString = selectCPUName(targetTriple, 21 | userCPUString); 22 | const auto cpu = llvm::StringSwitch(cpuString) 23 | .Case("i386", CK_i386) 24 | .Case("i486", CK_i486) 25 | .Case("winchip-c6", CK_WinChipC6) 26 | .Case("winchip2", CK_WinChip2) 27 | .Case("c3", CK_C3) 28 | .Case("i586", CK_i586) 29 | .Case("pentium", CK_Pentium) 30 | .Case("pentium-mmx", CK_PentiumMMX) 31 | .Case("i686", CK_i686) 32 | .Case("pentiumpro", CK_PentiumPro) 33 | .Case("pentium2", CK_Pentium2) 34 | .Case("pentium3", CK_Pentium3) 35 | .Case("pentium3m", CK_Pentium3M) 36 | .Case("pentium-m", CK_PentiumM) 37 | .Case("c3-2", CK_C3_2) 38 | .Case("yonah", CK_Yonah) 39 | .Case("pentium4", CK_Pentium4) 40 | .Case("pentium4m", CK_Pentium4M) 41 | .Case("prescott", CK_Prescott) 42 | .Case("nocona", CK_Nocona) 43 | .Case("core2", CK_Core2) 44 | .Case("penryn", CK_Penryn) 45 | .Case("bonnell", CK_Bonnell) 46 | .Case("atom", CK_Bonnell) // Legacy name. 47 | .Case("silvermont", CK_Silvermont) 48 | .Case("slm", CK_Silvermont) // Legacy name. 49 | .Case("nehalem", CK_Nehalem) 50 | .Case("corei7", CK_Nehalem) // Legacy name. 51 | .Case("westmere", CK_Westmere) 52 | .Case("sandybridge", CK_SandyBridge) 53 | .Case("corei7-avx", CK_SandyBridge) // Legacy name. 54 | .Case("ivybridge", CK_IvyBridge) 55 | .Case("core-avx-i", CK_IvyBridge) // Legacy name. 56 | .Case("haswell", CK_Haswell) 57 | .Case("core-avx2", CK_Haswell) // Legacy name. 58 | .Case("broadwell", CK_Broadwell) 59 | .Case("skylake", CK_Skylake) 60 | .Case("skx", CK_Skylake) // Legacy name. 61 | .Case("knl", CK_KNL) 62 | .Case("k6", CK_K6) 63 | .Case("k6-2", CK_K6_2) 64 | .Case("k6-3", CK_K6_3) 65 | .Case("athlon", CK_Athlon) 66 | .Case("athlon-tbird", CK_AthlonThunderbird) 67 | .Case("athlon-4", CK_Athlon4) 68 | .Case("athlon-xp", CK_AthlonXP) 69 | .Case("athlon-mp", CK_AthlonMP) 70 | .Case("athlon64", CK_Athlon64) 71 | .Case("athlon64-sse3", CK_Athlon64SSE3) 72 | .Case("athlon-fx", CK_AthlonFX) 73 | .Case("k8", CK_K8) 74 | .Case("k8-sse3", CK_K8SSE3) 75 | .Case("opteron", CK_Opteron) 76 | .Case("opteron-sse3", CK_OpteronSSE3) 77 | .Case("barcelona", CK_AMDFAM10) 78 | .Case("amdfam10", CK_AMDFAM10) 79 | .Case("btver1", CK_BTVER1) 80 | .Case("btver2", CK_BTVER2) 81 | .Case("bdver1", CK_BDVER1) 82 | .Case("bdver2", CK_BDVER2) 83 | .Case("bdver3", CK_BDVER3) 84 | .Case("bdver4", CK_BDVER4) 85 | .Case("x86-64", CK_x86_64) 86 | .Case("geode", CK_Geode) 87 | .Default(CK_Generic); 88 | 89 | // Perform any per-CPU checks necessary to determine if 90 | // this CPU is acceptable. 91 | switch (cpu) { 92 | case CK_Generic: 93 | throw std::runtime_error("No processor selected!"); 94 | 95 | case CK_i386: 96 | case CK_i486: 97 | case CK_WinChipC6: 98 | case CK_WinChip2: 99 | case CK_C3: 100 | case CK_i586: 101 | case CK_Pentium: 102 | case CK_PentiumMMX: 103 | case CK_i686: 104 | case CK_PentiumPro: 105 | case CK_Pentium2: 106 | case CK_Pentium3: 107 | case CK_Pentium3M: 108 | case CK_PentiumM: 109 | case CK_Yonah: 110 | case CK_C3_2: 111 | case CK_Pentium4: 112 | case CK_Pentium4M: 113 | case CK_Prescott: 114 | case CK_K6: 115 | case CK_K6_2: 116 | case CK_K6_3: 117 | case CK_Athlon: 118 | case CK_AthlonThunderbird: 119 | case CK_Athlon4: 120 | case CK_AthlonXP: 121 | case CK_AthlonMP: 122 | case CK_Geode: 123 | // Only accept certain architectures when compiling in 32-bit mode. 124 | if (targetTriple.getArch() != llvm::Triple::x86) { 125 | throw std::runtime_error("Invalid arch for 32-bit mode."); 126 | } 127 | 128 | // Fallthrough 129 | case CK_Nocona: 130 | case CK_Core2: 131 | case CK_Penryn: 132 | case CK_Bonnell: 133 | case CK_Silvermont: 134 | case CK_Nehalem: 135 | case CK_Westmere: 136 | case CK_SandyBridge: 137 | case CK_IvyBridge: 138 | case CK_Haswell: 139 | case CK_Broadwell: 140 | case CK_Skylake: 141 | case CK_KNL: 142 | case CK_Athlon64: 143 | case CK_Athlon64SSE3: 144 | case CK_AthlonFX: 145 | case CK_K8: 146 | case CK_K8SSE3: 147 | case CK_Opteron: 148 | case CK_OpteronSSE3: 149 | case CK_AMDFAM10: 150 | case CK_BTVER1: 151 | case CK_BTVER2: 152 | case CK_BDVER1: 153 | case CK_BDVER2: 154 | case CK_BDVER3: 155 | case CK_BDVER4: 156 | case CK_x86_64: 157 | return cpu; 158 | } 159 | llvm_unreachable("Unhandled CPU kind"); 160 | } 161 | 162 | } 163 | 164 | } 165 | -------------------------------------------------------------------------------- /lib/x86/Win64ABI.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | namespace llvm_abi { 9 | 10 | namespace x86 { 11 | 12 | Win64ABI::Win64ABI(llvm::Module* module) 13 | : llvmContext_(module->getContext()) { } 14 | 15 | Win64ABI::~Win64ABI() { } 16 | 17 | std::string Win64ABI::name() const { 18 | return "Win64"; 19 | } 20 | 21 | const ABITypeInfo& Win64ABI::typeInfo() const { 22 | llvm_unreachable("TODO"); 23 | } 24 | 25 | llvm::CallingConv::ID Win64ABI::getCallingConvention(const CallingConvention callingConvention) const { 26 | switch (callingConvention) { 27 | case CC_CDefault: 28 | case CC_CppDefault: 29 | return llvm::CallingConv::C; 30 | default: 31 | llvm_unreachable("Invalid calling convention for ABI."); 32 | } 33 | } 34 | 35 | llvm::FunctionType* Win64ABI::getFunctionType(const FunctionType& /*functionType*/) const { 36 | llvm_unreachable("TODO"); 37 | } 38 | 39 | llvm::AttributeList Win64ABI::getAttributes(const FunctionType& /*functionType*/, 40 | llvm::ArrayRef /*argumentTypes*/, 41 | const llvm::AttributeList /*existingAttributes*/) const { 42 | llvm_unreachable("TODO"); 43 | } 44 | 45 | llvm::Value* Win64ABI::createCall(Builder& /*builder*/, 46 | const FunctionType& /*functionType*/, 47 | std::function)> /*callBuilder*/, 48 | llvm::ArrayRef /*arguments*/) const { 49 | llvm_unreachable("TODO"); 50 | } 51 | 52 | std::unique_ptr Win64ABI::createFunctionEncoder(Builder& /*builder*/, 53 | const FunctionType& /*functionType*/, 54 | llvm::ArrayRef /*arguments*/) const { 55 | llvm_unreachable("TODO"); 56 | } 57 | 58 | } 59 | 60 | } 61 | 62 | -------------------------------------------------------------------------------- /test/CCodeGenerator.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LLVM_ABI_TEST_CCODEGENERATOR_HPP 2 | #define LLVM_ABI_TEST_CCODEGENERATOR_HPP 3 | 4 | #include 5 | #include 6 | 7 | namespace llvm_abi { 8 | 9 | class ABITypeInfo; 10 | struct TestFunctionType; 11 | class Type; 12 | 13 | /** 14 | * \brief C code generator. 15 | * 16 | * This class generates C code for a pair of callee and caller functions 17 | * for ABI function types. This allows function types to be passed to 18 | * a C compiler (Clang) and the output to be compared against the output 19 | * of the LLVM-ABI library. 20 | */ 21 | class CCodeGenerator { 22 | public: 23 | CCodeGenerator(const ABITypeInfo& typeInfo); 24 | 25 | std::string generatedSourceCode() const; 26 | 27 | std::string emitType(const Type& type); 28 | 29 | size_t emitFunctionTypes(const TestFunctionType& testFunctionType); 30 | 31 | void emitCalleeFunction(const TestFunctionType& testFunctionType, 32 | size_t functionId); 33 | 34 | void emitCallerFunction(const TestFunctionType& testFunctionType, 35 | size_t functionId); 36 | 37 | void emitCalleeAndCallerFunctions(const TestFunctionType& functionType); 38 | 39 | private: 40 | std::ostringstream sourceCodeStream_; 41 | const ABITypeInfo& typeInfo_; 42 | size_t arrayId_; 43 | size_t functionId_; 44 | size_t structId_; 45 | size_t unionId_; 46 | size_t vectorId_; 47 | 48 | }; 49 | 50 | } 51 | 52 | #endif -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Tests. 2 | # Run 'make test' or 'ctest' to execute these. 3 | 4 | find_package(Threads REQUIRED) 5 | 6 | add_executable(ParseTest 7 | CCodeGenerator.cpp 8 | ParseTest.cpp 9 | TokenStream.cpp 10 | ) 11 | 12 | target_link_libraries(ParseTest 13 | llvm-abi 14 | ${LLVM_LIBRARIES} 15 | tinfo 16 | ${CMAKE_DL_LIBS} 17 | ${CMAKE_THREAD_LIBS_INIT} 18 | ) 19 | 20 | # Search for Clang so we can compare against its output. 21 | set(CLANG_BINARY_SEARCH_NAMES 22 | clang-3.7 23 | clang-3.6 24 | clang-3.5 25 | clang-3.4 26 | clang-3.3 27 | clang 28 | ) 29 | 30 | find_program(CLANG_EXECUTABLE 31 | NAMES ${CLANG_BINARY_SEARCH_NAMES} 32 | DOC "Path to clang executable" 33 | ) 34 | 35 | add_subdirectory(x86_32) 36 | add_subdirectory(x86_64) 37 | -------------------------------------------------------------------------------- /test/TestFunctionType.hpp: -------------------------------------------------------------------------------- 1 | #ifndef TESTFUNCTIONTYPE_HPP 2 | #define TESTFUNCTIONTYPE_HPP 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | namespace llvm_abi { 10 | 11 | struct TestFunctionType { 12 | // ABI function type. 13 | FunctionType functionType; 14 | 15 | // Types to pass to varargs. 16 | llvm::SmallVector varArgsTypes; 17 | 18 | TestFunctionType(FunctionType argFunctionType, 19 | llvm::SmallVector argVarArgsTypes) 20 | : functionType(argFunctionType), 21 | varArgsTypes(argVarArgsTypes) { } 22 | }; 23 | 24 | } 25 | 26 | #endif -------------------------------------------------------------------------------- /test/TestSystem.hpp: -------------------------------------------------------------------------------- 1 | #ifndef TESTSYSTEM_HPP 2 | #define TESTSYSTEM_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | using namespace llvm_abi; 21 | 22 | class TestBuilder: public Builder { 23 | public: 24 | TestBuilder(llvm::Function& function) 25 | : function_(function), 26 | builder_(&(function.getEntryBlock())) { } 27 | 28 | IRBuilder& getEntryBuilder() { 29 | if (!function_.getEntryBlock().empty()) { 30 | builder_.SetInsertPoint(&(function_.getEntryBlock().front())); 31 | } 32 | return builder_; 33 | } 34 | 35 | IRBuilder& getBuilder() { 36 | builder_.SetInsertPoint(&(function_.getEntryBlock())); 37 | return builder_; 38 | } 39 | 40 | private: 41 | llvm::Function& function_; 42 | IRBuilder builder_; 43 | 44 | }; 45 | 46 | class TestSystem { 47 | public: 48 | TestSystem(const std::string& triple, 49 | const std::string& cpu) 50 | : context_(), 51 | module_("", context_), 52 | abi_(createABI(module_, llvm::Triple(triple), cpu)) { } 53 | 54 | ABI& abi() { 55 | return *abi_; 56 | } 57 | 58 | FunctionType makeCallerFunctionType(const TestFunctionType& testFunctionType) const { 59 | const auto& functionType = testFunctionType.functionType; 60 | if (!functionType.isVarArg()) { 61 | return functionType; 62 | } 63 | 64 | const auto& varArgsTypes = testFunctionType.varArgsTypes; 65 | 66 | llvm::SmallVector argumentTypes; 67 | argumentTypes.reserve(functionType.argumentTypes().size() + varArgsTypes.size()); 68 | 69 | for (const auto& argType: functionType.argumentTypes()) { 70 | argumentTypes.push_back(argType); 71 | } 72 | 73 | for (const auto& argType: varArgsTypes) { 74 | argumentTypes.push_back(argType); 75 | } 76 | 77 | return FunctionType(CC_CDefault, 78 | functionType.returnType(), 79 | argumentTypes, 80 | /*isVarArg=*/false); 81 | } 82 | 83 | void doTest(const std::string& testName, const TestFunctionType& testFunctionType) { 84 | const auto& calleeFunctionType = testFunctionType.functionType; 85 | const auto calleeFunction = llvm::cast(module_.getOrInsertFunction("callee", abi_->getFunctionType(calleeFunctionType)).getCallee()); 86 | const auto calleeAttributes = abi_->getAttributes(calleeFunctionType, 87 | calleeFunctionType.argumentTypes()); 88 | calleeFunction->setAttributes(calleeAttributes); 89 | 90 | const auto callerFunctionType = makeCallerFunctionType(testFunctionType); 91 | const auto callerFunction = llvm::cast(module_.getOrInsertFunction("caller", abi_->getFunctionType(callerFunctionType)).getCallee()); 92 | const auto callerAttributes = abi_->getAttributes(callerFunctionType, 93 | callerFunctionType.argumentTypes()); 94 | callerFunction->setAttributes(callerAttributes); 95 | 96 | const auto entryBasicBlock = llvm::BasicBlock::Create(context_, "", callerFunction); 97 | (void) entryBasicBlock; 98 | 99 | TestBuilder builder(*callerFunction); 100 | 101 | llvm::SmallVector encodedArgumentValues; 102 | for (auto it = callerFunction->arg_begin(); 103 | it != callerFunction->arg_end(); ++it) { 104 | encodedArgumentValues.push_back(&*it); 105 | } 106 | 107 | auto functionEncoder = abi_->createFunctionEncoder(builder, 108 | callerFunctionType, 109 | encodedArgumentValues); 110 | 111 | llvm::SmallVector arguments; 112 | 113 | for (size_t i = 0; i < functionEncoder->arguments().size(); i++) { 114 | const auto argValue = functionEncoder->arguments()[i]; 115 | const auto argType = callerFunctionType.argumentTypes()[i]; 116 | arguments.push_back(TypedValue(argValue, argType)); 117 | } 118 | 119 | const auto returnValue = abi_->createCall( 120 | builder, 121 | calleeFunctionType, 122 | [&](llvm::ArrayRef values) -> llvm::Value* { 123 | const auto callInst = builder.getBuilder().CreateCall(calleeFunction, values); 124 | const auto callAttributes = abi_->getAttributes(calleeFunctionType, 125 | callerFunctionType.argumentTypes()); 126 | callInst->setAttributes(callAttributes); 127 | return callInst; 128 | }, 129 | arguments 130 | ); 131 | 132 | functionEncoder->returnValue(returnValue); 133 | 134 | std::string filename; 135 | filename += "test-"; 136 | filename += abi_->name(); 137 | filename += "-" + testName; 138 | filename += ".output.ll"; 139 | 140 | std::ofstream file(filename.c_str()); 141 | file << "; Callee function type: " << std::endl; 142 | file << "; " << calleeFunctionType.toString() << std::endl; 143 | file << "; Caller function type: " << std::endl; 144 | file << "; " << callerFunctionType.toString() << std::endl; 145 | 146 | llvm::raw_os_ostream ostream(file); 147 | ostream << module_; 148 | } 149 | 150 | private: 151 | llvm::LLVMContext context_; 152 | llvm::Module module_; 153 | std::unique_ptr abi_; 154 | 155 | }; 156 | 157 | #endif 158 | -------------------------------------------------------------------------------- /test/TokenStream.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "TokenStream.hpp" 6 | 7 | namespace llvm_abi { 8 | 9 | TokenStream::TokenStream(const std::string& text) 10 | : text_(text), offset_(0) { 11 | consumeWhitespace(); 12 | } 13 | 14 | char TokenStream::peek() const { 15 | if (offset_ >= text_.length()) { 16 | return '\0'; 17 | } else { 18 | return text_[offset_]; 19 | } 20 | } 21 | 22 | void TokenStream::expect(const char expectedToken) const { 23 | if (peek() != expectedToken) { 24 | throw std::runtime_error(std::string("Didn't find expected token '") + std::string(1, expectedToken) + "'."); 25 | } 26 | } 27 | 28 | void TokenStream::expectAny(std::initializer_list expectedTokens) const { 29 | for (const auto& expectedToken: expectedTokens) { 30 | if (peek() == expectedToken) { 31 | return; 32 | } 33 | } 34 | throw std::runtime_error("Couldn't find expected token in list."); 35 | } 36 | 37 | void TokenStream::consume() { 38 | offset_++; 39 | consumeWhitespace(); 40 | } 41 | 42 | void TokenStream::consumeOne() { 43 | offset_++; 44 | } 45 | 46 | void TokenStream::consumeWhitespace() { 47 | while (true) { 48 | if (offset_ >= text_.length()) { 49 | break; 50 | } 51 | 52 | if (text_[offset_] == ' ') { 53 | // Ignore spaces. 54 | offset_++; 55 | continue; 56 | } 57 | 58 | break; 59 | } 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /test/TokenStream.hpp: -------------------------------------------------------------------------------- 1 | #ifndef TOKENSTREAM_HPP 2 | #define TOKENSTREAM_HPP 3 | 4 | #include 5 | #include 6 | 7 | namespace llvm_abi { 8 | 9 | class TokenStream { 10 | public: 11 | TokenStream(const std::string& text); 12 | 13 | char peek() const; 14 | 15 | void expect(char expectedToken) const; 16 | 17 | void expectAny(std::initializer_list expectedTokens) const; 18 | 19 | void consume(); 20 | 21 | void consumeOne(); 22 | 23 | void consumeWhitespace(); 24 | 25 | private: 26 | const std::string& text_; 27 | size_t offset_; 28 | 29 | }; 30 | 31 | } 32 | 33 | #endif -------------------------------------------------------------------------------- /test/x86_32/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | function(add_x86_32_call_test name) 3 | add_test(NAME "x86_32-${name}" COMMAND ParseTest "${CMAKE_CURRENT_SOURCE_DIR}/${name}.ll" "${CLANG_EXECUTABLE}") 4 | endfunction() 5 | 6 | add_subdirectory(Darwin) 7 | 8 | add_x86_32_call_test(Pass1Float) 9 | add_x86_32_call_test(Pass1Int) 10 | add_x86_32_call_test(Pass2Floats) 11 | add_x86_32_call_test(Pass2Ints) 12 | add_x86_32_call_test(Pass6IntsAndChar) 13 | add_x86_32_call_test(Pass6IntsAndPtr) 14 | add_x86_32_call_test(Pass8FloatsAndLongDouble) 15 | add_x86_32_call_test(Pass9Floats) 16 | add_x86_32_call_test(PassArrayStructDoubleIntInt) 17 | add_x86_32_call_test(PassArrayStructDoubleInt) 18 | add_x86_32_call_test(PassArrayStructDoubleIntLong) 19 | add_x86_32_call_test(PassCharShortIntLongLongPtr) 20 | add_x86_32_call_test(PassIntStructInt) 21 | add_x86_32_call_test(PassIntStructShortUintInt) 22 | add_x86_32_call_test(PassLongLongArrayAndReturnLongLongArray) 23 | add_x86_32_call_test(PassNamedStruct1Int) 24 | add_x86_32_call_test(PassNamedUnion1Int) 25 | add_x86_32_call_test(PassStruct1Float) 26 | add_x86_32_call_test(PassStruct1Int) 27 | add_x86_32_call_test(PassStruct2Floats) 28 | add_x86_32_call_test(PassStruct2Ints) 29 | add_x86_32_call_test(PassStruct3Ints) 30 | add_x86_32_call_test(PassStruct4Ints) 31 | add_x86_32_call_test(PassStruct5Ints) 32 | add_x86_32_call_test(PassStructArray1Char3Chars) 33 | add_x86_32_call_test(PassStructArrayVector4FloatsAndReturnStructArrayVector4Floats) 34 | add_x86_32_call_test(PassStructDoubleInt) 35 | add_x86_32_call_test(PassStructLongDouble) 36 | add_x86_32_call_test(PassStructLongDoubleLongDouble) 37 | add_x86_32_call_test(PassStructLongPtrAndReturnPtr) 38 | add_x86_32_call_test(PassStructLongPtr) 39 | add_x86_32_call_test(PassStructVector4FloatsAndReturnStructVector4Floats) 40 | add_x86_32_call_test(PassUnionArray5IntsFloat) 41 | add_x86_32_call_test(PassUnionDoubleInt) 42 | add_x86_32_call_test(PassVector4FloatsAndReturnVector4Floats) 43 | add_x86_32_call_test(ReturnChar) 44 | add_x86_32_call_test(ReturnDouble) 45 | add_x86_32_call_test(ReturnFloat) 46 | add_x86_32_call_test(ReturnInt) 47 | add_x86_32_call_test(ReturnLongDouble) 48 | add_x86_32_call_test(ReturnSChar) 49 | add_x86_32_call_test(ReturnShort) 50 | add_x86_32_call_test(ReturnStruct1Float) 51 | add_x86_32_call_test(ReturnStruct1Int) 52 | add_x86_32_call_test(ReturnStruct2Floats) 53 | add_x86_32_call_test(ReturnStruct2Ints) 54 | add_x86_32_call_test(ReturnStruct2Ptrs) 55 | add_x86_32_call_test(ReturnStruct3Ints) 56 | add_x86_32_call_test(ReturnStruct4Ints) 57 | add_x86_32_call_test(ReturnStruct5Ints) 58 | add_x86_32_call_test(ReturnStructEmptyArrayFloat) 59 | add_x86_32_call_test(ReturnStructFloatUnionEmpty) 60 | add_x86_32_call_test(ReturnStructLongInt) 61 | add_x86_32_call_test(ReturnUChar) 62 | add_x86_32_call_test(ReturnUShort) 63 | add_x86_32_call_test(VarArgsPassIntVACharShortIntFloatDouble) 64 | add_x86_32_call_test(VarArgsPassIntVAInt) 65 | add_x86_32_call_test(VarArgsPassIntVANone) 66 | add_x86_32_call_test(VarArgsPassIntVAUnionLongDoubleCharLong) 67 | add_x86_32_call_test(VarArgsPassPtrVAPtrIntDouble) 68 | add_x86_32_call_test(VarArgsPassPtrVAStructLongFloat) 69 | -------------------------------------------------------------------------------- /test/x86_32/Darwin/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | add_x86_32_call_test(DarwinReturnStructEmptyArrayFloat) 3 | add_x86_32_call_test(DarwinReturnStructFloatUnionEmpty) 4 | add_x86_32_call_test(DarwinReturnStructVector1Double) 5 | add_x86_32_call_test(DarwinReturnStructVector1LongLong) 6 | add_x86_32_call_test(DarwinReturnStructVector2Double) 7 | add_x86_32_call_test(DarwinReturnStructVector2Int) 8 | add_x86_32_call_test(DarwinReturnStructVector2LongLong) 9 | add_x86_32_call_test(DarwinReturnStructVector2Short) 10 | add_x86_32_call_test(DarwinReturnVector1Double) 11 | add_x86_32_call_test(DarwinReturnVector1LongLong) 12 | add_x86_32_call_test(DarwinReturnVector2Double) 13 | add_x86_32_call_test(DarwinReturnVector2Int) 14 | add_x86_32_call_test(DarwinReturnVector2LongLong) 15 | add_x86_32_call_test(DarwinReturnVector2Short) 16 | -------------------------------------------------------------------------------- /test/x86_32/Darwin/DarwinReturnStructEmptyArrayFloat.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-apple-darwin9 2 | ; FUNCTION-TYPE: {[0 x char], float} () 3 | 4 | declare float @callee() 5 | 6 | define float @caller() { 7 | %coerce1 = alloca { [0 x i8], float }, align 4 8 | %coerce = alloca { [0 x i8], float }, align 4 9 | %1 = call float @callee() 10 | %2 = bitcast { [0 x i8], float }* %coerce to float* 11 | store float %1, float* %2, align 1 12 | %3 = load { [0 x i8], float }* %coerce, align 4 13 | store { [0 x i8], float } %3, { [0 x i8], float }* %coerce1, align 4 14 | %4 = bitcast { [0 x i8], float }* %coerce1 to float* 15 | %5 = load float* %4, align 1 16 | ret float %5 17 | } 18 | -------------------------------------------------------------------------------- /test/x86_32/Darwin/DarwinReturnStructFloatUnionEmpty.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-apple-darwin9 2 | ; FUNCTION-TYPE: {float, union{}} () 3 | 4 | declare float @callee() 5 | 6 | define float @caller() { 7 | %coerce1 = alloca { float, {} }, align 4 8 | %coerce = alloca { float, {} }, align 4 9 | %1 = call float @callee() 10 | %coerce.dive = getelementptr { float, {} }* %coerce, i32 0, i32 0 11 | store float %1, float* %coerce.dive, align 1 12 | %2 = load { float, {} }* %coerce, align 4 13 | store { float, {} } %2, { float, {} }* %coerce1, align 4 14 | %coerce.dive2 = getelementptr { float, {} }* %coerce1, i32 0, i32 0 15 | %3 = load float* %coerce.dive2, align 1 16 | ret float %3 17 | } 18 | -------------------------------------------------------------------------------- /test/x86_32/Darwin/DarwinReturnStructVector1Double.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-apple-darwin9 2 | ; FUNCTION-TYPE: {<1 x double>} () 3 | 4 | declare void @callee({ <1 x double> }* noalias sret) 5 | 6 | define void @caller({ <1 x double> }* noalias sret %agg.result) { 7 | %1 = alloca { <1 x double> }, align 8 8 | call void @callee({ <1 x double> }* noalias sret %1) 9 | %2 = load { <1 x double> }* %1 10 | store { <1 x double> } %2, { <1 x double> }* %agg.result 11 | ret void 12 | } 13 | -------------------------------------------------------------------------------- /test/x86_32/Darwin/DarwinReturnStructVector1LongLong.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-apple-darwin9 2 | ; FUNCTION-TYPE: {<1 x longlong>} () 3 | 4 | declare void @callee({ <1 x i64> }* noalias sret) 5 | 6 | define void @caller({ <1 x i64> }* noalias sret %agg.result) { 7 | %1 = alloca { <1 x i64> }, align 8 8 | call void @callee({ <1 x i64> }* noalias sret %1) 9 | %2 = load { <1 x i64> }* %1 10 | store { <1 x i64> } %2, { <1 x i64> }* %agg.result 11 | ret void 12 | } 13 | -------------------------------------------------------------------------------- /test/x86_32/Darwin/DarwinReturnStructVector2Double.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-apple-darwin9 2 | ; FUNCTION-TYPE: {<2 x double>} () 3 | 4 | declare void @callee({ <2 x double> }* noalias sret) 5 | 6 | define void @caller({ <2 x double> }* noalias sret %agg.result) { 7 | %1 = alloca { <2 x double> }, align 16 8 | call void @callee({ <2 x double> }* noalias sret %1) 9 | %2 = load { <2 x double> }* %1 10 | store { <2 x double> } %2, { <2 x double> }* %agg.result 11 | ret void 12 | } 13 | -------------------------------------------------------------------------------- /test/x86_32/Darwin/DarwinReturnStructVector2Int.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-apple-darwin9 2 | ; FUNCTION-TYPE: {<2 x int>} () 3 | 4 | declare void @callee({ <2 x i32> }* noalias sret) 5 | 6 | define void @caller({ <2 x i32> }* noalias sret %agg.result) { 7 | %1 = alloca { <2 x i32> }, align 8 8 | call void @callee({ <2 x i32> }* noalias sret %1) 9 | %2 = load { <2 x i32> }* %1 10 | store { <2 x i32> } %2, { <2 x i32> }* %agg.result 11 | ret void 12 | } 13 | -------------------------------------------------------------------------------- /test/x86_32/Darwin/DarwinReturnStructVector2LongLong.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-apple-darwin9 2 | ; FUNCTION-TYPE: {<2 x longlong>} () 3 | 4 | declare void @callee({ <2 x i64> }* noalias sret) 5 | 6 | define void @caller({ <2 x i64> }* noalias sret %agg.result) { 7 | %1 = alloca { <2 x i64> }, align 16 8 | call void @callee({ <2 x i64> }* noalias sret %1) 9 | %2 = load { <2 x i64> }* %1 10 | store { <2 x i64> } %2, { <2 x i64> }* %agg.result 11 | ret void 12 | } 13 | -------------------------------------------------------------------------------- /test/x86_32/Darwin/DarwinReturnStructVector2Short.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-apple-darwin9 2 | ; FUNCTION-TYPE: {<2 x short>} () 3 | 4 | declare i32 @callee() 5 | 6 | define i32 @caller() { 7 | %coerce1 = alloca { <2 x i16> }, align 4 8 | %coerce = alloca { <2 x i16> }, align 4 9 | %1 = call i32 @callee() 10 | %coerce.dive = getelementptr { <2 x i16> }* %coerce, i32 0, i32 0 11 | %2 = bitcast <2 x i16>* %coerce.dive to i32* 12 | store i32 %1, i32* %2, align 1 13 | %3 = load { <2 x i16> }* %coerce, align 4 14 | store { <2 x i16> } %3, { <2 x i16> }* %coerce1, align 4 15 | %coerce.dive2 = getelementptr { <2 x i16> }* %coerce1, i32 0, i32 0 16 | %4 = bitcast <2 x i16>* %coerce.dive2 to i32* 17 | %5 = load i32* %4, align 1 18 | ret i32 %5 19 | } 20 | -------------------------------------------------------------------------------- /test/x86_32/Darwin/DarwinReturnVector1Double.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-apple-darwin9 2 | ; FUNCTION-TYPE: <1 x double> () 3 | 4 | declare i64 @callee() 5 | 6 | define i64 @caller() { 7 | %coerce1 = alloca <1 x double>, align 8 8 | %coerce = alloca <1 x double>, align 8 9 | %1 = call i64 @callee() 10 | %2 = bitcast <1 x double>* %coerce to i64* 11 | store i64 %1, i64* %2, align 1 12 | %3 = load <1 x double>* %coerce, align 8 13 | store <1 x double> %3, <1 x double>* %coerce1, align 8 14 | %4 = bitcast <1 x double>* %coerce1 to i64* 15 | %5 = load i64* %4, align 1 16 | ret i64 %5 17 | } 18 | -------------------------------------------------------------------------------- /test/x86_32/Darwin/DarwinReturnVector1LongLong.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-apple-darwin9 2 | ; FUNCTION-TYPE: <1 x longlong> () 3 | 4 | declare i64 @callee() 5 | 6 | define i64 @caller() { 7 | %coerce1 = alloca <1 x i64>, align 8 8 | %coerce = alloca <1 x i64>, align 8 9 | %1 = call i64 @callee() 10 | %2 = bitcast <1 x i64>* %coerce to i64* 11 | store i64 %1, i64* %2, align 1 12 | %3 = load <1 x i64>* %coerce, align 8 13 | store <1 x i64> %3, <1 x i64>* %coerce1, align 8 14 | %4 = bitcast <1 x i64>* %coerce1 to i64* 15 | %5 = load i64* %4, align 1 16 | ret i64 %5 17 | } 18 | -------------------------------------------------------------------------------- /test/x86_32/Darwin/DarwinReturnVector2Double.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-apple-darwin9 2 | ; FUNCTION-TYPE: <2 x double> () 3 | 4 | declare <2 x i64> @callee() 5 | 6 | define <2 x i64> @caller() { 7 | %coerce1 = alloca <2 x double>, align 16 8 | %coerce = alloca <2 x double>, align 16 9 | %1 = call <2 x i64> @callee() 10 | %2 = bitcast <2 x double>* %coerce to <2 x i64>* 11 | store <2 x i64> %1, <2 x i64>* %2, align 1 12 | %3 = load <2 x double>* %coerce, align 16 13 | store <2 x double> %3, <2 x double>* %coerce1, align 16 14 | %4 = bitcast <2 x double>* %coerce1 to <2 x i64>* 15 | %5 = load <2 x i64>* %4, align 1 16 | ret <2 x i64> %5 17 | } 18 | -------------------------------------------------------------------------------- /test/x86_32/Darwin/DarwinReturnVector2Int.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-apple-darwin9 2 | ; FUNCTION-TYPE: <2 x int> () 3 | 4 | declare void @callee(<2 x i32>* noalias sret) 5 | 6 | define void @caller(<2 x i32>* noalias sret %agg.result) { 7 | %1 = alloca <2 x i32>, align 8 8 | call void @callee(<2 x i32>* noalias sret %1) 9 | %2 = load <2 x i32>* %1 10 | store <2 x i32> %2, <2 x i32>* %agg.result 11 | ret void 12 | } 13 | -------------------------------------------------------------------------------- /test/x86_32/Darwin/DarwinReturnVector2LongLong.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-apple-darwin9 2 | ; FUNCTION-TYPE: <2 x longlong> () 3 | 4 | declare <2 x i64> @callee() 5 | 6 | define <2 x i64> @caller() { 7 | %1 = call <2 x i64> @callee() 8 | ret <2 x i64> %1 9 | } 10 | -------------------------------------------------------------------------------- /test/x86_32/Darwin/DarwinReturnVector2Short.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-apple-darwin9 2 | ; FUNCTION-TYPE: <2 x short> () 3 | 4 | declare i32 @callee() 5 | 6 | define i32 @caller() { 7 | %coerce1 = alloca <2 x i16>, align 4 8 | %coerce = alloca <2 x i16>, align 4 9 | %1 = call i32 @callee() 10 | %2 = bitcast <2 x i16>* %coerce to i32* 11 | store i32 %1, i32* %2, align 1 12 | %3 = load <2 x i16>* %coerce, align 4 13 | store <2 x i16> %3, <2 x i16>* %coerce1, align 4 14 | %4 = bitcast <2 x i16>* %coerce1 to i32* 15 | %5 = load i32* %4, align 1 16 | ret i32 %5 17 | } 18 | -------------------------------------------------------------------------------- /test/x86_32/Pass1Float.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: void (float) 3 | 4 | declare void @callee(float) 5 | 6 | define void @caller(float) { 7 | call void @callee(float %0) 8 | ret void 9 | } 10 | -------------------------------------------------------------------------------- /test/x86_32/Pass1Int.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: void (int) 3 | 4 | declare void @callee(i32) 5 | 6 | define void @caller(i32) { 7 | call void @callee(i32 %0) 8 | ret void 9 | } 10 | -------------------------------------------------------------------------------- /test/x86_32/Pass2Floats.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: void (float, float) 3 | 4 | declare void @callee(float, float) 5 | 6 | define void @caller(float, float) { 7 | call void @callee(float %0, float %1) 8 | ret void 9 | } 10 | -------------------------------------------------------------------------------- /test/x86_32/Pass2Ints.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: void (int, int) 3 | 4 | declare void @callee(i32, i32) 5 | 6 | define void @caller(i32, i32) { 7 | call void @callee(i32 %0, i32 %1) 8 | ret void 9 | } 10 | -------------------------------------------------------------------------------- /test/x86_32/Pass6IntsAndChar.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: void (int, int, int, int, int, int, char) 3 | 4 | declare void @callee(i32, i32, i32, i32, i32, i32, i8 signext) 5 | 6 | define void @caller(i32, i32, i32, i32, i32, i32, i8 signext) { 7 | call void @callee(i32 %0, i32 %1, i32 %2, i32 %3, i32 %4, i32 %5, i8 signext %6) 8 | ret void 9 | } 10 | -------------------------------------------------------------------------------- /test/x86_32/Pass6IntsAndPtr.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: void (int, int, int, int, int, int, ptr) 3 | 4 | declare void @callee(i32, i32, i32, i32, i32, i32, i8*) 5 | 6 | define void @caller(i32, i32, i32, i32, i32, i32, i8*) { 7 | call void @callee(i32 %0, i32 %1, i32 %2, i32 %3, i32 %4, i32 %5, i8* %6) 8 | ret void 9 | } 10 | -------------------------------------------------------------------------------- /test/x86_32/Pass8FloatsAndLongDouble.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: void (float, float, float, float, float, float, float, float, longdouble) 3 | 4 | declare void @callee(float, float, float, float, float, float, float, float, x86_fp80) 5 | 6 | define void @caller(float, float, float, float, float, float, float, float, x86_fp80) { 7 | call void @callee(float %0, float %1, float %2, float %3, float %4, float %5, float %6, float %7, x86_fp80 %8) 8 | ret void 9 | } 10 | -------------------------------------------------------------------------------- /test/x86_32/Pass9Floats.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: void (float, float, float, float, float, float, float, float, float) 3 | 4 | declare void @callee(float, float, float, float, float, float, float, float, float) 5 | 6 | define void @caller(float, float, float, float, float, float, float, float, float) { 7 | call void @callee(float %0, float %1, float %2, float %3, float %4, float %5, float %6, float %7, float %8) 8 | ret void 9 | } 10 | -------------------------------------------------------------------------------- /test/x86_32/PassArrayStructDoubleInt.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: void ([1 x {double, int }]) 3 | 4 | declare void @callee([1 x { double, i32 }]* byval align 4) 5 | 6 | define void @caller([1 x { double, i32 }]* byval align 4) { 7 | %indirect.arg.mem = alloca [1 x { double, i32 }], align 4 8 | %2 = load [1 x { double, i32 }]* %0, align 4 9 | store [1 x { double, i32 }] %2, [1 x { double, i32 }]* %indirect.arg.mem, align 4 10 | call void @callee([1 x { double, i32 }]* byval align 4 %indirect.arg.mem) 11 | ret void 12 | } 13 | -------------------------------------------------------------------------------- /test/x86_32/PassArrayStructDoubleIntInt.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: void ([1 x {double, int, int }]) 3 | 4 | declare void @callee([1 x { double, i32, i32 }]* byval align 4) 5 | 6 | define void @caller([1 x { double, i32, i32 }]* byval align 4) { 7 | %indirect.arg.mem = alloca [1 x { double, i32, i32 }], align 4 8 | %2 = load [1 x { double, i32, i32 }]* %0, align 4 9 | store [1 x { double, i32, i32 }] %2, [1 x { double, i32, i32 }]* %indirect.arg.mem, align 4 10 | call void @callee([1 x { double, i32, i32 }]* byval align 4 %indirect.arg.mem) 11 | ret void 12 | } 13 | -------------------------------------------------------------------------------- /test/x86_32/PassArrayStructDoubleIntLong.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: void ([1 x {double, int, long }]) 3 | 4 | declare void @callee([1 x { double, i32, i32 }]* byval align 4) 5 | 6 | define void @caller([1 x { double, i32, i32 }]* byval align 4) { 7 | %indirect.arg.mem = alloca [1 x { double, i32, i32 }], align 4 8 | %2 = load [1 x { double, i32, i32 }]* %0, align 4 9 | store [1 x { double, i32, i32 }] %2, [1 x { double, i32, i32 }]* %indirect.arg.mem, align 4 10 | call void @callee([1 x { double, i32, i32 }]* byval align 4 %indirect.arg.mem) 11 | ret void 12 | } 13 | -------------------------------------------------------------------------------- /test/x86_32/PassCharShortIntLongLongPtr.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: void (char, short, int, longlong, ptr) 3 | 4 | declare void @callee(i8 signext, i16 signext, i32, i64, i8*) 5 | 6 | define void @caller(i8 signext, i16 signext, i32, i64, i8*) { 7 | call void @callee(i8 signext %0, i16 signext %1, i32 %2, i64 %3, i8* %4) 8 | ret void 9 | } 10 | -------------------------------------------------------------------------------- /test/x86_32/PassIntStructInt.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: void (int, { int }) 3 | 4 | declare void @callee(i32, i32) 5 | 6 | define void @caller(i32, i32) { 7 | %expand.source.arg = alloca { i32 }, align 4 8 | %expand.dest.arg = alloca { i32 }, align 4 9 | %3 = getelementptr { i32 }* %expand.dest.arg, i32 0, i32 0 10 | store i32 %1, i32* %3, align 4 11 | %4 = load { i32 }* %expand.dest.arg, align 4 12 | store { i32 } %4, { i32 }* %expand.source.arg, align 4 13 | %5 = getelementptr { i32 }* %expand.source.arg, i32 0, i32 0 14 | %6 = load i32* %5, align 4 15 | call void @callee(i32 %0, i32 %6) 16 | ret void 17 | } 18 | -------------------------------------------------------------------------------- /test/x86_32/PassIntStructShortUintInt.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: void (int, {short, uint, int}) 3 | 4 | declare void @callee(i32, { i16, i32, i32 }* byval align 4) 5 | 6 | define void @caller(i32, { i16, i32, i32 }* byval align 4) { 7 | %indirect.arg.mem = alloca { i16, i32, i32 }, align 4 8 | %3 = load { i16, i32, i32 }* %1, align 4 9 | store { i16, i32, i32 } %3, { i16, i32, i32 }* %indirect.arg.mem, align 4 10 | call void @callee(i32 %0, { i16, i32, i32 }* byval align 4 %indirect.arg.mem) 11 | ret void 12 | } 13 | -------------------------------------------------------------------------------- /test/x86_32/PassLongLongArrayAndReturnLongLongArray.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: {[3 x longlong]} (int, int, int, int, {[2 x longlong]}, int) 3 | 4 | declare void @callee({ [3 x i64] }* noalias sret, i32, i32, i32, i32, { [2 x i64] }* byval align 4, i32) 5 | 6 | define void @caller({ [3 x i64] }* noalias sret %agg.result, i32, i32, i32, i32, { [2 x i64] }* byval align 4, i32) { 7 | %indirect.arg.mem = alloca { [2 x i64] }, align 4 8 | %7 = alloca { [3 x i64] }, align 4 9 | %8 = load { [2 x i64] }* %4, align 4 10 | store { [2 x i64] } %8, { [2 x i64] }* %indirect.arg.mem, align 4 11 | call void @callee({ [3 x i64] }* noalias sret %7, i32 %0, i32 %1, i32 %2, i32 %3, { [2 x i64] }* byval align 4 %indirect.arg.mem, i32 %5) 12 | %9 = load { [3 x i64] }* %7 13 | store { [3 x i64] } %9, { [3 x i64] }* %agg.result 14 | ret void 15 | } 16 | -------------------------------------------------------------------------------- /test/x86_32/PassNamedStruct1Int.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: void (struct NamedStruct{ int }) 3 | 4 | %NamedStruct = type { i32 } 5 | 6 | declare void @callee(i32) 7 | 8 | define void @caller(i32) { 9 | %expand.source.arg = alloca %NamedStruct, align 4 10 | %expand.dest.arg = alloca %NamedStruct, align 4 11 | %2 = getelementptr %NamedStruct* %expand.dest.arg, i32 0, i32 0 12 | store i32 %0, i32* %2, align 4 13 | %3 = load %NamedStruct* %expand.dest.arg, align 4 14 | store %NamedStruct %3, %NamedStruct* %expand.source.arg, align 4 15 | %4 = getelementptr %NamedStruct* %expand.source.arg, i32 0, i32 0 16 | %5 = load i32* %4, align 4 17 | call void @callee(i32 %5) 18 | ret void 19 | } 20 | -------------------------------------------------------------------------------- /test/x86_32/PassNamedUnion1Int.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: void (union NamedUnion{ int }) 3 | 4 | %NamedUnion = type { i32 } 5 | 6 | declare void @callee(%NamedUnion* byval align 4) 7 | 8 | define void @caller(%NamedUnion* byval align 4) { 9 | %indirect.arg.mem = alloca %NamedUnion, align 4 10 | %2 = load %NamedUnion* %0, align 4 11 | store %NamedUnion %2, %NamedUnion* %indirect.arg.mem, align 4 12 | call void @callee(%NamedUnion* byval align 4 %indirect.arg.mem) 13 | ret void 14 | } 15 | -------------------------------------------------------------------------------- /test/x86_32/PassStruct1Float.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: void ({ float }) 3 | 4 | declare void @callee(float) 5 | 6 | define void @caller(float) { 7 | %expand.source.arg = alloca { float }, align 4 8 | %expand.dest.arg = alloca { float }, align 4 9 | %2 = getelementptr { float }* %expand.dest.arg, i32 0, i32 0 10 | store float %0, float* %2, align 4 11 | %3 = load { float }* %expand.dest.arg, align 4 12 | store { float } %3, { float }* %expand.source.arg, align 4 13 | %4 = getelementptr { float }* %expand.source.arg, i32 0, i32 0 14 | %5 = load float* %4, align 4 15 | call void @callee(float %5) 16 | ret void 17 | } 18 | -------------------------------------------------------------------------------- /test/x86_32/PassStruct1Int.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: void ({ int }) 3 | 4 | declare void @callee(i32) 5 | 6 | define void @caller(i32) { 7 | %expand.source.arg = alloca { i32 }, align 4 8 | %expand.dest.arg = alloca { i32 }, align 4 9 | %2 = getelementptr { i32 }* %expand.dest.arg, i32 0, i32 0 10 | store i32 %0, i32* %2, align 4 11 | %3 = load { i32 }* %expand.dest.arg, align 4 12 | store { i32 } %3, { i32 }* %expand.source.arg, align 4 13 | %4 = getelementptr { i32 }* %expand.source.arg, i32 0, i32 0 14 | %5 = load i32* %4, align 4 15 | call void @callee(i32 %5) 16 | ret void 17 | } 18 | -------------------------------------------------------------------------------- /test/x86_32/PassStruct2Floats.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: void ({ float, float }) 3 | 4 | declare void @callee(float, float) 5 | 6 | define void @caller(float, float) { 7 | %expand.source.arg = alloca { float, float }, align 4 8 | %expand.dest.arg = alloca { float, float }, align 4 9 | %3 = getelementptr { float, float }* %expand.dest.arg, i32 0, i32 0 10 | store float %0, float* %3, align 4 11 | %4 = getelementptr { float, float }* %expand.dest.arg, i32 0, i32 1 12 | store float %1, float* %4, align 4 13 | %5 = load { float, float }* %expand.dest.arg, align 4 14 | store { float, float } %5, { float, float }* %expand.source.arg, align 4 15 | %6 = getelementptr { float, float }* %expand.source.arg, i32 0, i32 0 16 | %7 = load float* %6, align 4 17 | %8 = getelementptr { float, float }* %expand.source.arg, i32 0, i32 1 18 | %9 = load float* %8, align 4 19 | call void @callee(float %7, float %9) 20 | ret void 21 | } 22 | -------------------------------------------------------------------------------- /test/x86_32/PassStruct2Ints.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: void ({ int, int }) 3 | 4 | declare void @callee(i32, i32) 5 | 6 | define void @caller(i32, i32) { 7 | %expand.source.arg = alloca { i32, i32 }, align 4 8 | %expand.dest.arg = alloca { i32, i32 }, align 4 9 | %3 = getelementptr { i32, i32 }* %expand.dest.arg, i32 0, i32 0 10 | store i32 %0, i32* %3, align 4 11 | %4 = getelementptr { i32, i32 }* %expand.dest.arg, i32 0, i32 1 12 | store i32 %1, i32* %4, align 4 13 | %5 = load { i32, i32 }* %expand.dest.arg, align 4 14 | store { i32, i32 } %5, { i32, i32 }* %expand.source.arg, align 4 15 | %6 = getelementptr { i32, i32 }* %expand.source.arg, i32 0, i32 0 16 | %7 = load i32* %6, align 4 17 | %8 = getelementptr { i32, i32 }* %expand.source.arg, i32 0, i32 1 18 | %9 = load i32* %8, align 4 19 | call void @callee(i32 %7, i32 %9) 20 | ret void 21 | } 22 | -------------------------------------------------------------------------------- /test/x86_32/PassStruct3Ints.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: void ({ int, int, int }) 3 | 4 | declare void @callee(i32, i32, i32) 5 | 6 | define void @caller(i32, i32, i32) { 7 | %expand.source.arg = alloca { i32, i32, i32 }, align 4 8 | %expand.dest.arg = alloca { i32, i32, i32 }, align 4 9 | %4 = getelementptr { i32, i32, i32 }* %expand.dest.arg, i32 0, i32 0 10 | store i32 %0, i32* %4, align 4 11 | %5 = getelementptr { i32, i32, i32 }* %expand.dest.arg, i32 0, i32 1 12 | store i32 %1, i32* %5, align 4 13 | %6 = getelementptr { i32, i32, i32 }* %expand.dest.arg, i32 0, i32 2 14 | store i32 %2, i32* %6, align 4 15 | %7 = load { i32, i32, i32 }* %expand.dest.arg, align 4 16 | store { i32, i32, i32 } %7, { i32, i32, i32 }* %expand.source.arg, align 4 17 | %8 = getelementptr { i32, i32, i32 }* %expand.source.arg, i32 0, i32 0 18 | %9 = load i32* %8, align 4 19 | %10 = getelementptr { i32, i32, i32 }* %expand.source.arg, i32 0, i32 1 20 | %11 = load i32* %10, align 4 21 | %12 = getelementptr { i32, i32, i32 }* %expand.source.arg, i32 0, i32 2 22 | %13 = load i32* %12, align 4 23 | call void @callee(i32 %9, i32 %11, i32 %13) 24 | ret void 25 | } 26 | -------------------------------------------------------------------------------- /test/x86_32/PassStruct4Ints.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: void ({ int, int, int, int }) 3 | 4 | declare void @callee(i32, i32, i32, i32) 5 | 6 | define void @caller(i32, i32, i32, i32) { 7 | %expand.source.arg = alloca { i32, i32, i32, i32 }, align 4 8 | %expand.dest.arg = alloca { i32, i32, i32, i32 }, align 4 9 | %5 = getelementptr { i32, i32, i32, i32 }* %expand.dest.arg, i32 0, i32 0 10 | store i32 %0, i32* %5, align 4 11 | %6 = getelementptr { i32, i32, i32, i32 }* %expand.dest.arg, i32 0, i32 1 12 | store i32 %1, i32* %6, align 4 13 | %7 = getelementptr { i32, i32, i32, i32 }* %expand.dest.arg, i32 0, i32 2 14 | store i32 %2, i32* %7, align 4 15 | %8 = getelementptr { i32, i32, i32, i32 }* %expand.dest.arg, i32 0, i32 3 16 | store i32 %3, i32* %8, align 4 17 | %9 = load { i32, i32, i32, i32 }* %expand.dest.arg, align 4 18 | store { i32, i32, i32, i32 } %9, { i32, i32, i32, i32 }* %expand.source.arg, align 4 19 | %10 = getelementptr { i32, i32, i32, i32 }* %expand.source.arg, i32 0, i32 0 20 | %11 = load i32* %10, align 4 21 | %12 = getelementptr { i32, i32, i32, i32 }* %expand.source.arg, i32 0, i32 1 22 | %13 = load i32* %12, align 4 23 | %14 = getelementptr { i32, i32, i32, i32 }* %expand.source.arg, i32 0, i32 2 24 | %15 = load i32* %14, align 4 25 | %16 = getelementptr { i32, i32, i32, i32 }* %expand.source.arg, i32 0, i32 3 26 | %17 = load i32* %16, align 4 27 | call void @callee(i32 %11, i32 %13, i32 %15, i32 %17) 28 | ret void 29 | } 30 | -------------------------------------------------------------------------------- /test/x86_32/PassStruct5Ints.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: void ({ int, int, int, int, int }) 3 | 4 | declare void @callee({ i32, i32, i32, i32, i32 }* byval align 4) 5 | 6 | define void @caller({ i32, i32, i32, i32, i32 }* byval align 4) { 7 | %indirect.arg.mem = alloca { i32, i32, i32, i32, i32 }, align 4 8 | %2 = load { i32, i32, i32, i32, i32 }* %0, align 4 9 | store { i32, i32, i32, i32, i32 } %2, { i32, i32, i32, i32, i32 }* %indirect.arg.mem, align 4 10 | call void @callee({ i32, i32, i32, i32, i32 }* byval align 4 %indirect.arg.mem) 11 | ret void 12 | } 13 | -------------------------------------------------------------------------------- /test/x86_32/PassStructArray1Char3Chars.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: void ({[8 x char], char, char, char}) 3 | 4 | declare void @callee({ [8 x i8], i8, i8, i8 }* byval align 4) 5 | 6 | define void @caller({ [8 x i8], i8, i8, i8 }* byval align 4) { 7 | %indirect.arg.mem = alloca { [8 x i8], i8, i8, i8 }, align 4 8 | %2 = load { [8 x i8], i8, i8, i8 }* %0, align 4 9 | store { [8 x i8], i8, i8, i8 } %2, { [8 x i8], i8, i8, i8 }* %indirect.arg.mem, align 4 10 | call void @callee({ [8 x i8], i8, i8, i8 }* byval align 4 %indirect.arg.mem) 11 | ret void 12 | } 13 | -------------------------------------------------------------------------------- /test/x86_32/PassStructArrayVector4FloatsAndReturnStructArrayVector4Floats.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: {[1 x <4 x float>]} ({[1 x <4 x float>]}) 3 | 4 | declare void @callee({ [1 x <4 x float>] }* noalias sret, { [1 x <4 x float>] }* byval align 4) 5 | 6 | define void @caller({ [1 x <4 x float>] }* noalias sret %agg.result, { [1 x <4 x float>] }* byval align 4) { 7 | %indirect.arg.mem = alloca { [1 x <4 x float>] }, align 16 8 | %2 = alloca { [1 x <4 x float>] }, align 16 9 | %coerce = alloca { [1 x <4 x float>] }, align 16 10 | %3 = bitcast { [1 x <4 x float>] }* %coerce to i8* 11 | %4 = bitcast { [1 x <4 x float>] }* %0 to i8* 12 | call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %3, i8* align 4 %4, i32 16, i1 false) 13 | %5 = load { [1 x <4 x float>] }* %coerce, align 16 14 | store { [1 x <4 x float>] } %5, { [1 x <4 x float>] }* %indirect.arg.mem, align 16 15 | call void @callee({ [1 x <4 x float>] }* noalias sret %2, { [1 x <4 x float>] }* byval align 4 %indirect.arg.mem) 16 | %6 = load { [1 x <4 x float>] }* %2 17 | store { [1 x <4 x float>] } %6, { [1 x <4 x float>] }* %agg.result 18 | ret void 19 | } 20 | 21 | ; Function Attrs: nounwind 22 | declare void @llvm.memcpy.p0i8.p0i8.i32(i8* nocapture, i8* nocapture readonly, i32, i32, i1) #0 23 | 24 | attributes #0 = { argmemonly nounwind } 25 | -------------------------------------------------------------------------------- /test/x86_32/PassStructDoubleInt.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: void ({ double, int }) 3 | 4 | declare void @callee(double, i32) 5 | 6 | define void @caller(double, i32) { 7 | %expand.source.arg = alloca { double, i32 }, align 4 8 | %expand.dest.arg = alloca { double, i32 }, align 4 9 | %3 = getelementptr { double, i32 }* %expand.dest.arg, i32 0, i32 0 10 | store double %0, double* %3, align 4 11 | %4 = getelementptr { double, i32 }* %expand.dest.arg, i32 0, i32 1 12 | store i32 %1, i32* %4, align 4 13 | %5 = load { double, i32 }* %expand.dest.arg, align 4 14 | store { double, i32 } %5, { double, i32 }* %expand.source.arg, align 4 15 | %6 = getelementptr { double, i32 }* %expand.source.arg, i32 0, i32 0 16 | %7 = load double* %6, align 4 17 | %8 = getelementptr { double, i32 }* %expand.source.arg, i32 0, i32 1 18 | %9 = load i32* %8, align 4 19 | call void @callee(double %7, i32 %9) 20 | ret void 21 | } 22 | -------------------------------------------------------------------------------- /test/x86_32/PassStructLongDouble.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: void ({ longdouble }) 3 | 4 | declare void @callee({ x86_fp80 }* byval align 4) 5 | 6 | define void @caller({ x86_fp80 }* byval align 4) { 7 | %indirect.arg.mem = alloca { x86_fp80 }, align 4 8 | %2 = load { x86_fp80 }* %0, align 4 9 | store { x86_fp80 } %2, { x86_fp80 }* %indirect.arg.mem, align 4 10 | call void @callee({ x86_fp80 }* byval align 4 %indirect.arg.mem) 11 | ret void 12 | } 13 | -------------------------------------------------------------------------------- /test/x86_32/PassStructLongDoubleLongDouble.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: void ({ longdouble, longdouble }) 3 | 4 | declare void @callee({ x86_fp80, x86_fp80 }* byval align 4) 5 | 6 | define void @caller({ x86_fp80, x86_fp80 }* byval align 4) { 7 | %indirect.arg.mem = alloca { x86_fp80, x86_fp80 }, align 4 8 | %2 = load { x86_fp80, x86_fp80 }* %0, align 4 9 | store { x86_fp80, x86_fp80 } %2, { x86_fp80, x86_fp80 }* %indirect.arg.mem, align 4 10 | call void @callee({ x86_fp80, x86_fp80 }* byval align 4 %indirect.arg.mem) 11 | ret void 12 | } 13 | -------------------------------------------------------------------------------- /test/x86_32/PassStructLongPtr.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: void ({ long, ptr }) 3 | 4 | declare void @callee(i32, i8*) 5 | 6 | define void @caller(i32, i8*) { 7 | %expand.source.arg = alloca { i32, i8* }, align 4 8 | %expand.dest.arg = alloca { i32, i8* }, align 4 9 | %3 = getelementptr { i32, i8* }* %expand.dest.arg, i32 0, i32 0 10 | store i32 %0, i32* %3, align 4 11 | %4 = getelementptr { i32, i8* }* %expand.dest.arg, i32 0, i32 1 12 | store i8* %1, i8** %4, align 4 13 | %5 = load { i32, i8* }* %expand.dest.arg, align 4 14 | store { i32, i8* } %5, { i32, i8* }* %expand.source.arg, align 4 15 | %6 = getelementptr { i32, i8* }* %expand.source.arg, i32 0, i32 0 16 | %7 = load i32* %6, align 4 17 | %8 = getelementptr { i32, i8* }* %expand.source.arg, i32 0, i32 1 18 | %9 = load i8** %8, align 4 19 | call void @callee(i32 %7, i8* %9) 20 | ret void 21 | } 22 | -------------------------------------------------------------------------------- /test/x86_32/PassStructLongPtrAndReturnPtr.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: ptr ({ long, ptr }) 3 | 4 | declare i8* @callee(i32, i8*) 5 | 6 | define i8* @caller(i32, i8*) { 7 | %expand.source.arg = alloca { i32, i8* }, align 4 8 | %expand.dest.arg = alloca { i32, i8* }, align 4 9 | %3 = getelementptr { i32, i8* }* %expand.dest.arg, i32 0, i32 0 10 | store i32 %0, i32* %3, align 4 11 | %4 = getelementptr { i32, i8* }* %expand.dest.arg, i32 0, i32 1 12 | store i8* %1, i8** %4, align 4 13 | %5 = load { i32, i8* }* %expand.dest.arg, align 4 14 | store { i32, i8* } %5, { i32, i8* }* %expand.source.arg, align 4 15 | %6 = getelementptr { i32, i8* }* %expand.source.arg, i32 0, i32 0 16 | %7 = load i32* %6, align 4 17 | %8 = getelementptr { i32, i8* }* %expand.source.arg, i32 0, i32 1 18 | %9 = load i8** %8, align 4 19 | %10 = call i8* @callee(i32 %7, i8* %9) 20 | ret i8* %10 21 | } 22 | -------------------------------------------------------------------------------- /test/x86_32/PassStructVector4FloatsAndReturnStructVector4Floats.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: {<4 x float>} ({<4 x float>}) 3 | 4 | declare void @callee({ <4 x float> }* noalias sret, { <4 x float> }* byval align 4) 5 | 6 | define void @caller({ <4 x float> }* noalias sret %agg.result, { <4 x float> }* byval align 4) { 7 | %indirect.arg.mem = alloca { <4 x float> }, align 16 8 | %2 = alloca { <4 x float> }, align 16 9 | %coerce = alloca { <4 x float> }, align 16 10 | %3 = bitcast { <4 x float> }* %coerce to i8* 11 | %4 = bitcast { <4 x float> }* %0 to i8* 12 | call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %3, i8* align 4 %4, i32 16, i1 false) 13 | %5 = load { <4 x float> }* %coerce, align 16 14 | store { <4 x float> } %5, { <4 x float> }* %indirect.arg.mem, align 16 15 | call void @callee({ <4 x float> }* noalias sret %2, { <4 x float> }* byval align 4 %indirect.arg.mem) 16 | %6 = load { <4 x float> }* %2 17 | store { <4 x float> } %6, { <4 x float> }* %agg.result 18 | ret void 19 | } 20 | 21 | ; Function Attrs: nounwind 22 | declare void @llvm.memcpy.p0i8.p0i8.i32(i8* nocapture, i8* nocapture readonly, i32, i32, i1) #0 23 | 24 | attributes #0 = { argmemonly nounwind } 25 | -------------------------------------------------------------------------------- /test/x86_32/PassUnionArray5IntsFloat.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: void (union{ [5 x int], float }) 3 | 4 | declare void @callee({ [5 x i32] }* byval align 4) 5 | 6 | define void @caller({ [5 x i32] }* byval align 4) { 7 | %indirect.arg.mem = alloca { [5 x i32] }, align 4 8 | %2 = load { [5 x i32] }* %0, align 4 9 | store { [5 x i32] } %2, { [5 x i32] }* %indirect.arg.mem, align 4 10 | call void @callee({ [5 x i32] }* byval align 4 %indirect.arg.mem) 11 | ret void 12 | } 13 | -------------------------------------------------------------------------------- /test/x86_32/PassUnionDoubleInt.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: void (union{ double, int }) 3 | 4 | declare void @callee({ double }* byval align 4) 5 | 6 | define void @caller({ double }* byval align 4) { 7 | %indirect.arg.mem = alloca { double }, align 4 8 | %2 = load { double }* %0, align 4 9 | store { double } %2, { double }* %indirect.arg.mem, align 4 10 | call void @callee({ double }* byval align 4 %indirect.arg.mem) 11 | ret void 12 | } 13 | -------------------------------------------------------------------------------- /test/x86_32/PassVector4FloatsAndReturnVector4Floats.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: <4 x float> (<4 x float>) 3 | 4 | declare <4 x float> @callee(<4 x float>) 5 | 6 | define <4 x float> @caller(<4 x float>) { 7 | %2 = call <4 x float> @callee(<4 x float> %0) 8 | ret <4 x float> %2 9 | } 10 | -------------------------------------------------------------------------------- /test/x86_32/ReturnChar.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: char () 3 | 4 | declare signext i8 @callee() 5 | 6 | define signext i8 @caller() { 7 | %1 = call signext i8 @callee() 8 | ret i8 %1 9 | } 10 | -------------------------------------------------------------------------------- /test/x86_32/ReturnDouble.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: double () 3 | 4 | declare double @callee() 5 | 6 | define double @caller() { 7 | %1 = call double @callee() 8 | ret double %1 9 | } 10 | -------------------------------------------------------------------------------- /test/x86_32/ReturnFloat.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: float () 3 | 4 | declare float @callee() 5 | 6 | define float @caller() { 7 | %1 = call float @callee() 8 | ret float %1 9 | } 10 | -------------------------------------------------------------------------------- /test/x86_32/ReturnInt.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: int () 3 | 4 | declare i32 @callee() 5 | 6 | define i32 @caller() { 7 | %1 = call i32 @callee() 8 | ret i32 %1 9 | } 10 | -------------------------------------------------------------------------------- /test/x86_32/ReturnLongDouble.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: longdouble () 3 | 4 | declare x86_fp80 @callee() 5 | 6 | define x86_fp80 @caller() { 7 | %1 = call x86_fp80 @callee() 8 | ret x86_fp80 %1 9 | } 10 | -------------------------------------------------------------------------------- /test/x86_32/ReturnSChar.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: schar () 3 | 4 | declare signext i8 @callee() 5 | 6 | define signext i8 @caller() { 7 | %1 = call signext i8 @callee() 8 | ret i8 %1 9 | } 10 | -------------------------------------------------------------------------------- /test/x86_32/ReturnShort.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: short () 3 | 4 | declare signext i16 @callee() 5 | 6 | define signext i16 @caller() { 7 | %1 = call signext i16 @callee() 8 | ret i16 %1 9 | } 10 | -------------------------------------------------------------------------------- /test/x86_32/ReturnStruct1Float.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: {float} () 3 | 4 | declare void @callee({ float }* noalias sret) 5 | 6 | define void @caller({ float }* noalias sret %agg.result) { 7 | %1 = alloca { float }, align 4 8 | call void @callee({ float }* noalias sret %1) 9 | %2 = load { float }* %1 10 | store { float } %2, { float }* %agg.result 11 | ret void 12 | } 13 | -------------------------------------------------------------------------------- /test/x86_32/ReturnStruct1Int.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: {int} () 3 | 4 | declare void @callee({ i32 }* noalias sret) 5 | 6 | define void @caller({ i32 }* noalias sret %agg.result) { 7 | %1 = alloca { i32 }, align 4 8 | call void @callee({ i32 }* noalias sret %1) 9 | %2 = load { i32 }* %1 10 | store { i32 } %2, { i32 }* %agg.result 11 | ret void 12 | } 13 | -------------------------------------------------------------------------------- /test/x86_32/ReturnStruct2Floats.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: {float, float} () 3 | 4 | declare void @callee({ float, float }* noalias sret) 5 | 6 | define void @caller({ float, float }* noalias sret %agg.result) { 7 | %1 = alloca { float, float }, align 4 8 | call void @callee({ float, float }* noalias sret %1) 9 | %2 = load { float, float }* %1 10 | store { float, float } %2, { float, float }* %agg.result 11 | ret void 12 | } 13 | -------------------------------------------------------------------------------- /test/x86_32/ReturnStruct2Ints.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: {int, int} () 3 | 4 | declare void @callee({ i32, i32 }* noalias sret) 5 | 6 | define void @caller({ i32, i32 }* noalias sret %agg.result) { 7 | %1 = alloca { i32, i32 }, align 4 8 | call void @callee({ i32, i32 }* noalias sret %1) 9 | %2 = load { i32, i32 }* %1 10 | store { i32, i32 } %2, { i32, i32 }* %agg.result 11 | ret void 12 | } 13 | -------------------------------------------------------------------------------- /test/x86_32/ReturnStruct2Ptrs.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: {ptr, ptr} () 3 | 4 | declare void @callee({ i8*, i8* }* noalias sret) 5 | 6 | define void @caller({ i8*, i8* }* noalias sret %agg.result) { 7 | %1 = alloca { i8*, i8* }, align 4 8 | call void @callee({ i8*, i8* }* noalias sret %1) 9 | %2 = load { i8*, i8* }* %1 10 | store { i8*, i8* } %2, { i8*, i8* }* %agg.result 11 | ret void 12 | } 13 | -------------------------------------------------------------------------------- /test/x86_32/ReturnStruct3Ints.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: {int, int, int} () 3 | 4 | declare void @callee({ i32, i32, i32 }* noalias sret) 5 | 6 | define void @caller({ i32, i32, i32 }* noalias sret %agg.result) { 7 | %1 = alloca { i32, i32, i32 }, align 4 8 | call void @callee({ i32, i32, i32 }* noalias sret %1) 9 | %2 = load { i32, i32, i32 }* %1 10 | store { i32, i32, i32 } %2, { i32, i32, i32 }* %agg.result 11 | ret void 12 | } 13 | -------------------------------------------------------------------------------- /test/x86_32/ReturnStruct4Ints.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: {int, int, int, int} () 3 | 4 | declare void @callee({ i32, i32, i32, i32 }* noalias sret) 5 | 6 | define void @caller({ i32, i32, i32, i32 }* noalias sret %agg.result) { 7 | %1 = alloca { i32, i32, i32, i32 }, align 4 8 | call void @callee({ i32, i32, i32, i32 }* noalias sret %1) 9 | %2 = load { i32, i32, i32, i32 }* %1 10 | store { i32, i32, i32, i32 } %2, { i32, i32, i32, i32 }* %agg.result 11 | ret void 12 | } 13 | -------------------------------------------------------------------------------- /test/x86_32/ReturnStruct5Ints.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: {int, int, int, int, int} () 3 | 4 | declare void @callee({ i32, i32, i32, i32, i32 }* noalias sret) 5 | 6 | define void @caller({ i32, i32, i32, i32, i32 }* noalias sret %agg.result) { 7 | %1 = alloca { i32, i32, i32, i32, i32 }, align 4 8 | call void @callee({ i32, i32, i32, i32, i32 }* noalias sret %1) 9 | %2 = load { i32, i32, i32, i32, i32 }* %1 10 | store { i32, i32, i32, i32, i32 } %2, { i32, i32, i32, i32, i32 }* %agg.result 11 | ret void 12 | } 13 | -------------------------------------------------------------------------------- /test/x86_32/ReturnStructEmptyArrayFloat.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: {[0 x char], float} () 3 | 4 | declare void @callee({ [0 x i8], float }* noalias sret) 5 | 6 | define void @caller({ [0 x i8], float }* noalias sret %agg.result) { 7 | %1 = alloca { [0 x i8], float }, align 4 8 | call void @callee({ [0 x i8], float }* noalias sret %1) 9 | %2 = load { [0 x i8], float }* %1 10 | store { [0 x i8], float } %2, { [0 x i8], float }* %agg.result 11 | ret void 12 | } 13 | -------------------------------------------------------------------------------- /test/x86_32/ReturnStructFloatUnionEmpty.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: {float, union{}} () 3 | 4 | declare void @callee({ float, {} }* noalias sret) 5 | 6 | define void @caller({ float, {} }* noalias sret %agg.result) { 7 | %1 = alloca { float, {} }, align 4 8 | call void @callee({ float, {} }* noalias sret %1) 9 | %2 = load { float, {} }* %1 10 | store { float, {} } %2, { float, {} }* %agg.result 11 | ret void 12 | } 13 | -------------------------------------------------------------------------------- /test/x86_32/ReturnStructLongInt.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: {long, int} () 3 | 4 | declare void @callee({ i32, i32 }* noalias sret) 5 | 6 | define void @caller({ i32, i32 }* noalias sret %agg.result) { 7 | %1 = alloca { i32, i32 }, align 4 8 | call void @callee({ i32, i32 }* noalias sret %1) 9 | %2 = load { i32, i32 }* %1 10 | store { i32, i32 } %2, { i32, i32 }* %agg.result 11 | ret void 12 | } 13 | -------------------------------------------------------------------------------- /test/x86_32/ReturnUChar.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: uchar () 3 | 4 | declare zeroext i8 @callee() 5 | 6 | define zeroext i8 @caller() { 7 | %1 = call zeroext i8 @callee() 8 | ret i8 %1 9 | } 10 | -------------------------------------------------------------------------------- /test/x86_32/ReturnUShort.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: ushort () 3 | 4 | declare zeroext i16 @callee() 5 | 6 | define zeroext i16 @caller() { 7 | %1 = call zeroext i16 @callee() 8 | ret i16 %1 9 | } 10 | -------------------------------------------------------------------------------- /test/x86_32/VarArgsPassIntVACharShortIntFloatDouble.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: void (int, ...(char, short, int, float, double)) 3 | 4 | declare void @callee(i32, ...) 5 | 6 | define void @caller(i32, i8 signext, i16 signext, i32, float, double) { 7 | %7 = sext i8 %1 to i32 8 | %8 = sext i16 %2 to i32 9 | %9 = fpext float %4 to double 10 | call void (i32, ...)* @callee(i32 %0, i32 %7, i32 %8, i32 %3, double %9, double %5) 11 | ret void 12 | } 13 | -------------------------------------------------------------------------------- /test/x86_32/VarArgsPassIntVAInt.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: void (int, ...(int)) 3 | 4 | declare void @callee(i32, ...) 5 | 6 | define void @caller(i32, i32) { 7 | call void (i32, ...)* @callee(i32 %0, i32 %1) 8 | ret void 9 | } 10 | -------------------------------------------------------------------------------- /test/x86_32/VarArgsPassIntVANone.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: void (int, ...()) 3 | 4 | declare void @callee(i32, ...) 5 | 6 | define void @caller(i32) { 7 | call void (i32, ...)* @callee(i32 %0) 8 | ret void 9 | } 10 | -------------------------------------------------------------------------------- /test/x86_32/VarArgsPassIntVAUnionLongDoubleCharLong.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: void (int, ...(union { longdouble, char, long })) 3 | 4 | declare void @callee(i32, ...) 5 | 6 | define void @caller(i32, { x86_fp80 }* byval align 4) { 7 | %indirect.arg.mem = alloca { x86_fp80 }, align 4 8 | %3 = load { x86_fp80 }* %1, align 4 9 | store { x86_fp80 } %3, { x86_fp80 }* %indirect.arg.mem, align 4 10 | call void (i32, ...)* @callee(i32 %0, { x86_fp80 }* byval align 4 %indirect.arg.mem) 11 | ret void 12 | } 13 | -------------------------------------------------------------------------------- /test/x86_32/VarArgsPassPtrVAPtrIntDouble.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: void (ptr, ...(ptr, int, double)) 3 | 4 | declare void @callee(i8*, ...) 5 | 6 | define void @caller(i8*, i8*, i32, double) { 7 | call void (i8*, ...)* @callee(i8* %0, i8* %1, i32 %2, double %3) 8 | ret void 9 | } 10 | -------------------------------------------------------------------------------- /test/x86_32/VarArgsPassPtrVAStructLongFloat.ll: -------------------------------------------------------------------------------- 1 | ; ABI: i386-none-linux-gnu 2 | ; FUNCTION-TYPE: void (ptr, ...({ long, float })) 3 | 4 | declare void @callee(i8*, ...) 5 | 6 | define void @caller(i8*, i32, float) { 7 | %expand.source.arg = alloca { i32, float }, align 4 8 | %expand.dest.arg = alloca { i32, float }, align 4 9 | %4 = getelementptr { i32, float }* %expand.dest.arg, i32 0, i32 0 10 | store i32 %1, i32* %4, align 4 11 | %5 = getelementptr { i32, float }* %expand.dest.arg, i32 0, i32 1 12 | store float %2, float* %5, align 4 13 | %6 = load { i32, float }* %expand.dest.arg, align 4 14 | store { i32, float } %6, { i32, float }* %expand.source.arg, align 4 15 | %7 = getelementptr { i32, float }* %expand.source.arg, i32 0, i32 0 16 | %8 = load i32* %7, align 4 17 | %9 = getelementptr { i32, float }* %expand.source.arg, i32 0, i32 1 18 | %10 = load float* %9, align 4 19 | call void (i8*, ...)* @callee(i8* %0, i32 %8, float %10) 20 | ret void 21 | } 22 | -------------------------------------------------------------------------------- /test/x86_64/AVXPassVarArgs.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; Sandy Bridge has the AVX support this test needs. 3 | ; CPU: sandybridge 4 | ; FUNCTION-TYPE: void (int, ...(<8 x float>)) 5 | 6 | declare void @callee(i32, ...) 7 | 8 | define void @caller(i32, <8 x float>) { 9 | call void (i32, ...)* @callee(i32 %0, <8 x float> %1) 10 | ret void 11 | } 12 | -------------------------------------------------------------------------------- /test/x86_64/AVXStructArrayVector8Floats.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; Sandy Bridge has the AVX support this test needs. 3 | ; CPU: sandybridge 4 | ; FUNCTION-TYPE: {[1 x <8 x float>]} ({[1 x <8 x float>]}) 5 | 6 | declare <8 x float> @callee(<8 x float>) 7 | 8 | define <8 x float> @caller(<8 x float> %coerce) { 9 | %coerce4 = alloca { [1 x <8 x float>] }, align 32 10 | %coerce2 = alloca { [1 x <8 x float>] }, align 32 11 | %coerce.arg.source = alloca { [1 x <8 x float>] }, align 32 12 | %coerce.mem = alloca { [1 x <8 x float>] }, align 32 13 | %coerce.dive = getelementptr { [1 x <8 x float>] }* %coerce.mem, i32 0, i32 0 14 | %1 = bitcast [1 x <8 x float>]* %coerce.dive to <8 x float>* 15 | store <8 x float> %coerce, <8 x float>* %1, align 1 16 | %2 = load { [1 x <8 x float>] }* %coerce.mem 17 | store { [1 x <8 x float>] } %2, { [1 x <8 x float>] }* %coerce.arg.source 18 | %coerce.dive1 = getelementptr { [1 x <8 x float>] }* %coerce.arg.source, i32 0, i32 0 19 | %3 = bitcast [1 x <8 x float>]* %coerce.dive1 to <8 x float>* 20 | %4 = load <8 x float>* %3, align 1 21 | %5 = call <8 x float> @callee(<8 x float> %4) 22 | %coerce.dive3 = getelementptr { [1 x <8 x float>] }* %coerce2, i32 0, i32 0 23 | %6 = bitcast [1 x <8 x float>]* %coerce.dive3 to <8 x float>* 24 | store <8 x float> %5, <8 x float>* %6, align 1 25 | %7 = load { [1 x <8 x float>] }* %coerce2, align 32 26 | store { [1 x <8 x float>] } %7, { [1 x <8 x float>] }* %coerce4, align 32 27 | %coerce.dive5 = getelementptr { [1 x <8 x float>] }* %coerce4, i32 0, i32 0 28 | %8 = bitcast [1 x <8 x float>]* %coerce.dive5 to <8 x float>* 29 | %9 = load <8 x float>* %8, align 1 30 | ret <8 x float> %9 31 | } 32 | -------------------------------------------------------------------------------- /test/x86_64/AVXStructVector8Floats.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; Sandy Bridge has the AVX support this test needs. 3 | ; CPU: sandybridge 4 | ; FUNCTION-TYPE: {<8 x float>} ({<8 x float>}) 5 | 6 | declare <8 x float> @callee(<8 x float>) 7 | 8 | define <8 x float> @caller(<8 x float> %coerce) { 9 | %coerce4 = alloca { <8 x float> }, align 32 10 | %coerce2 = alloca { <8 x float> }, align 32 11 | %coerce.arg.source = alloca { <8 x float> }, align 32 12 | %coerce.mem = alloca { <8 x float> }, align 32 13 | %coerce.dive = getelementptr { <8 x float> }* %coerce.mem, i32 0, i32 0 14 | store <8 x float> %coerce, <8 x float>* %coerce.dive, align 1 15 | %1 = load { <8 x float> }* %coerce.mem 16 | store { <8 x float> } %1, { <8 x float> }* %coerce.arg.source 17 | %coerce.dive1 = getelementptr { <8 x float> }* %coerce.arg.source, i32 0, i32 0 18 | %2 = load <8 x float>* %coerce.dive1, align 1 19 | %3 = call <8 x float> @callee(<8 x float> %2) 20 | %coerce.dive3 = getelementptr { <8 x float> }* %coerce2, i32 0, i32 0 21 | store <8 x float> %3, <8 x float>* %coerce.dive3, align 1 22 | %4 = load { <8 x float> }* %coerce2, align 32 23 | store { <8 x float> } %4, { <8 x float> }* %coerce4, align 32 24 | %coerce.dive5 = getelementptr { <8 x float> }* %coerce4, i32 0, i32 0 25 | %5 = load <8 x float>* %coerce.dive5, align 1 26 | ret <8 x float> %5 27 | } 28 | -------------------------------------------------------------------------------- /test/x86_64/AVXVector8Floats.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; Sandy Bridge has the AVX support this test needs. 3 | ; CPU: sandybridge 4 | ; FUNCTION-TYPE: <8 x float> (<8 x float>) 5 | 6 | declare <8 x float> @callee(<8 x float>) 7 | 8 | define <8 x float> @caller(<8 x float>) { 9 | %2 = call <8 x float> @callee(<8 x float> %0) 10 | ret <8 x float> %2 11 | } 12 | -------------------------------------------------------------------------------- /test/x86_64/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | function(add_x86_64_call_test name) 3 | add_test(NAME "x86_64-${name}" COMMAND ParseTest "${CMAKE_CURRENT_SOURCE_DIR}/${name}.ll" "${CLANG_EXECUTABLE}") 4 | endfunction() 5 | 6 | add_x86_64_call_test(AVXPassVarArgs) 7 | add_x86_64_call_test(AVXStructArrayVector8Floats) 8 | add_x86_64_call_test(AVXStructVector8Floats) 9 | add_x86_64_call_test(AVXVector8Floats) 10 | add_x86_64_call_test(NoAVXPassVarArgs) 11 | add_x86_64_call_test(NoAVXStructArrayVector8Floats) 12 | add_x86_64_call_test(NoAVXStructVector8Floats) 13 | add_x86_64_call_test(NoAVXVector8Floats) 14 | add_x86_64_call_test(Pass1Float) 15 | add_x86_64_call_test(Pass1Int) 16 | add_x86_64_call_test(Pass2Floats) 17 | add_x86_64_call_test(Pass2Ints) 18 | add_x86_64_call_test(Pass6IntsAndChar) 19 | add_x86_64_call_test(Pass6IntsAndPtr) 20 | add_x86_64_call_test(Pass8FloatsAndLongDouble) 21 | add_x86_64_call_test(Pass9Floats) 22 | add_x86_64_call_test(PassArrayStructDoubleInt) 23 | add_x86_64_call_test(PassArrayStructDoubleIntInt) 24 | add_x86_64_call_test(PassArrayStructDoubleIntLong) 25 | add_x86_64_call_test(PassCharShortIntLongLongPtr) 26 | add_x86_64_call_test(PassIntStructInt) 27 | add_x86_64_call_test(PassIntStructShortUintInt) 28 | add_x86_64_call_test(PassLongLongArrayAndReturnLongLongArray) 29 | add_x86_64_call_test(PassNamedStruct1Int) 30 | add_x86_64_call_test(PassNamedStruct2Ints) 31 | add_x86_64_call_test(PassNamedStructPtrInt) 32 | add_x86_64_call_test(PassNamedUnion1Int) 33 | add_x86_64_call_test(PassStruct1Float) 34 | add_x86_64_call_test(PassStruct1Int) 35 | add_x86_64_call_test(PassStruct2Floats) 36 | add_x86_64_call_test(PassStruct2Ints) 37 | add_x86_64_call_test(PassStruct3Ints) 38 | add_x86_64_call_test(PassStruct4Ints) 39 | add_x86_64_call_test(PassStruct5Ints) 40 | add_x86_64_call_test(PassStructArray1Char3Chars) 41 | add_x86_64_call_test(PassStructArrayVector4FloatsAndReturnStructArrayVector4Floats) 42 | add_x86_64_call_test(PassStructDoubleInt) 43 | add_x86_64_call_test(PassStructLongDouble) 44 | add_x86_64_call_test(PassStructLongDoubleLongDouble) 45 | add_x86_64_call_test(PassStructLongPtr) 46 | add_x86_64_call_test(PassStructLongPtrAndReturnPtr) 47 | add_x86_64_call_test(PassStructVector4FloatsAndReturnStructVector4Floats) 48 | add_x86_64_call_test(PassUnionArray5IntsFloat) 49 | add_x86_64_call_test(PassUnionDoubleInt) 50 | add_x86_64_call_test(PassVector4FloatsAndReturnVector4Floats) 51 | add_x86_64_call_test(ReturnChar) 52 | add_x86_64_call_test(ReturnDouble) 53 | add_x86_64_call_test(ReturnFloat) 54 | add_x86_64_call_test(ReturnInt) 55 | add_x86_64_call_test(ReturnLongDouble) 56 | add_x86_64_call_test(ReturnSChar) 57 | add_x86_64_call_test(ReturnShort) 58 | add_x86_64_call_test(ReturnStruct1Float) 59 | add_x86_64_call_test(ReturnStruct1Int) 60 | add_x86_64_call_test(ReturnStruct2Floats) 61 | add_x86_64_call_test(ReturnStruct2Ints) 62 | add_x86_64_call_test(ReturnStruct2Ptrs) 63 | add_x86_64_call_test(ReturnStruct3Ints) 64 | add_x86_64_call_test(ReturnStruct4Ints) 65 | add_x86_64_call_test(ReturnStruct5Ints) 66 | add_x86_64_call_test(ReturnStructEmptyArrayFloat) 67 | add_x86_32_call_test(ReturnStructFloatUnionEmpty) 68 | add_x86_64_call_test(ReturnStructLongInt) 69 | add_x86_64_call_test(ReturnUChar) 70 | add_x86_64_call_test(ReturnUnionLongDoubleInt) 71 | add_x86_64_call_test(ReturnUShort) 72 | add_x86_64_call_test(VarArgsPassIntVACharShortIntFloatDouble) 73 | add_x86_64_call_test(VarArgsPassIntVAInt) 74 | add_x86_64_call_test(VarArgsPassIntVAUnionLongDoubleCharLong) 75 | add_x86_64_call_test(VarArgsPassIntVANone) 76 | add_x86_64_call_test(VarArgsPassPtrVAPtrIntDouble) 77 | add_x86_64_call_test(VarArgsPassPtrVAStructLongFloat) 78 | -------------------------------------------------------------------------------- /test/x86_64/NoAVXPassVarArgs.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: void (int, ...(<8 x float>)) 3 | 4 | declare void @callee(i32, ...) 5 | 6 | define void @caller(i32, <8 x float>* byval align 32) { 7 | %indirect.arg.mem = alloca <8 x float>, align 32 8 | %3 = load <8 x float>* %1, align 32 9 | store <8 x float> %3, <8 x float>* %indirect.arg.mem, align 32 10 | call void (i32, ...)* @callee(i32 %0, <8 x float>* byval align 32 %indirect.arg.mem) 11 | ret void 12 | } 13 | -------------------------------------------------------------------------------- /test/x86_64/NoAVXStructArrayVector8Floats.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: {[1 x <8 x float>]} ({[1 x <8 x float>]}) 3 | 4 | declare void @callee({ [1 x <8 x float>] }* noalias sret, { [1 x <8 x float>] }* byval align 32) 5 | 6 | define void @caller({ [1 x <8 x float>] }* noalias sret %agg.result, { [1 x <8 x float>] }* byval align 32) { 7 | %indirect.arg.mem = alloca { [1 x <8 x float>] }, align 32 8 | %2 = alloca { [1 x <8 x float>] }, align 32 9 | %3 = load { [1 x <8 x float>] }* %0, align 32 10 | store { [1 x <8 x float>] } %3, { [1 x <8 x float>] }* %indirect.arg.mem, align 32 11 | call void @callee({ [1 x <8 x float>] }* noalias sret %2, { [1 x <8 x float>] }* byval align 32 %indirect.arg.mem) 12 | %4 = load { [1 x <8 x float>] }* %2 13 | store { [1 x <8 x float>] } %4, { [1 x <8 x float>] }* %agg.result 14 | ret void 15 | } 16 | -------------------------------------------------------------------------------- /test/x86_64/NoAVXStructVector8Floats.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: {<8 x float>} ({<8 x float>}) 3 | 4 | declare void @callee({ <8 x float> }* noalias sret, { <8 x float> }* byval align 32) 5 | 6 | define void @caller({ <8 x float> }* noalias sret %agg.result, { <8 x float> }* byval align 32) { 7 | %indirect.arg.mem = alloca { <8 x float> }, align 32 8 | %2 = alloca { <8 x float> }, align 32 9 | %3 = load { <8 x float> }* %0, align 32 10 | store { <8 x float> } %3, { <8 x float> }* %indirect.arg.mem, align 32 11 | call void @callee({ <8 x float> }* noalias sret %2, { <8 x float> }* byval align 32 %indirect.arg.mem) 12 | %4 = load { <8 x float> }* %2 13 | store { <8 x float> } %4, { <8 x float> }* %agg.result 14 | ret void 15 | } 16 | -------------------------------------------------------------------------------- /test/x86_64/NoAVXVector8Floats.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: <8 x float> (<8 x float>) 3 | 4 | declare <8 x float> @callee(<8 x float>* byval align 32) 5 | 6 | define <8 x float> @caller(<8 x float>* byval align 32) { 7 | %indirect.arg.mem = alloca <8 x float>, align 32 8 | %2 = load <8 x float>* %0, align 32 9 | store <8 x float> %2, <8 x float>* %indirect.arg.mem, align 32 10 | %3 = call <8 x float> @callee(<8 x float>* byval align 32 %indirect.arg.mem) 11 | ret <8 x float> %3 12 | } 13 | -------------------------------------------------------------------------------- /test/x86_64/Pass1Float.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: void (float) 3 | 4 | declare void @callee(float) 5 | 6 | define void @caller(float) { 7 | call void @callee(float %0) 8 | ret void 9 | } 10 | -------------------------------------------------------------------------------- /test/x86_64/Pass1Int.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: void (int) 3 | 4 | declare void @callee(i32) 5 | 6 | define void @caller(i32) { 7 | call void @callee(i32 %0) 8 | ret void 9 | } 10 | -------------------------------------------------------------------------------- /test/x86_64/Pass2Floats.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: void (float, float) 3 | 4 | declare void @callee(float, float) 5 | 6 | define void @caller(float, float) { 7 | call void @callee(float %0, float %1) 8 | ret void 9 | } 10 | -------------------------------------------------------------------------------- /test/x86_64/Pass2Ints.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: void (int, int) 3 | 4 | declare void @callee(i32, i32) 5 | 6 | define void @caller(i32, i32) { 7 | call void @callee(i32 %0, i32 %1) 8 | ret void 9 | } 10 | -------------------------------------------------------------------------------- /test/x86_64/Pass6IntsAndChar.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: void (int, int, int, int, int, int, char) 3 | 4 | declare void @callee(i32, i32, i32, i32, i32, i32, i8 signext) 5 | 6 | define void @caller(i32, i32, i32, i32, i32, i32, i8 signext) { 7 | call void @callee(i32 %0, i32 %1, i32 %2, i32 %3, i32 %4, i32 %5, i8 signext %6) 8 | ret void 9 | } 10 | -------------------------------------------------------------------------------- /test/x86_64/Pass6IntsAndPtr.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: void (int, int, int, int, int, int, ptr) 3 | 4 | declare void @callee(i32, i32, i32, i32, i32, i32, i8*) 5 | 6 | define void @caller(i32, i32, i32, i32, i32, i32, i8*) { 7 | call void @callee(i32 %0, i32 %1, i32 %2, i32 %3, i32 %4, i32 %5, i8* %6) 8 | ret void 9 | } 10 | -------------------------------------------------------------------------------- /test/x86_64/Pass8FloatsAndLongDouble.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: void (float, float, float, float, float, float, float, float, longdouble) 3 | 4 | declare void @callee(float, float, float, float, float, float, float, float, x86_fp80) 5 | 6 | define void @caller(float, float, float, float, float, float, float, float, x86_fp80) { 7 | call void @callee(float %0, float %1, float %2, float %3, float %4, float %5, float %6, float %7, x86_fp80 %8) 8 | ret void 9 | } 10 | -------------------------------------------------------------------------------- /test/x86_64/Pass9Floats.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: void (float, float, float, float, float, float, float, float, float) 3 | 4 | declare void @callee(float, float, float, float, float, float, float, float, float) 5 | 6 | define void @caller(float, float, float, float, float, float, float, float, float) { 7 | call void @callee(float %0, float %1, float %2, float %3, float %4, float %5, float %6, float %7, float %8) 8 | ret void 9 | } 10 | -------------------------------------------------------------------------------- /test/x86_64/PassArrayStructDoubleInt.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: void ([1 x {double, int }]) 3 | 4 | declare void @callee(double, i32) 5 | 6 | define void @caller(double %coerce0, i32 %coerce1) { 7 | %coerce.arg.source = alloca [1 x { double, i32 }], align 8 8 | %coerce.mem = alloca [1 x { double, i32 }], align 8 9 | %1 = bitcast [1 x { double, i32 }]* %coerce.mem to { double, i32 }* 10 | %2 = getelementptr { double, i32 }* %1, i32 0, i32 0 11 | store double %coerce0, double* %2 12 | %3 = getelementptr { double, i32 }* %1, i32 0, i32 1 13 | store i32 %coerce1, i32* %3 14 | %4 = load [1 x { double, i32 }]* %coerce.mem 15 | store [1 x { double, i32 }] %4, [1 x { double, i32 }]* %coerce.arg.source 16 | %5 = bitcast [1 x { double, i32 }]* %coerce.arg.source to { double, i32 }* 17 | %6 = getelementptr { double, i32 }* %5, i32 0, i32 0 18 | %7 = load double* %6, align 1 19 | %8 = getelementptr { double, i32 }* %5, i32 0, i32 1 20 | %9 = load i32* %8, align 1 21 | call void @callee(double %7, i32 %9) 22 | ret void 23 | } 24 | -------------------------------------------------------------------------------- /test/x86_64/PassArrayStructDoubleIntInt.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: void ([1 x {double, int, int }]) 3 | 4 | declare void @callee(double, i64) 5 | 6 | define void @caller(double %coerce0, i64 %coerce1) { 7 | %coerce.arg.source = alloca [1 x { double, i32, i32 }], align 8 8 | %coerce.mem = alloca [1 x { double, i32, i32 }], align 8 9 | %1 = bitcast [1 x { double, i32, i32 }]* %coerce.mem to { double, i64 }* 10 | %2 = getelementptr { double, i64 }* %1, i32 0, i32 0 11 | store double %coerce0, double* %2 12 | %3 = getelementptr { double, i64 }* %1, i32 0, i32 1 13 | store i64 %coerce1, i64* %3 14 | %4 = load [1 x { double, i32, i32 }]* %coerce.mem 15 | store [1 x { double, i32, i32 }] %4, [1 x { double, i32, i32 }]* %coerce.arg.source 16 | %5 = bitcast [1 x { double, i32, i32 }]* %coerce.arg.source to { double, i64 }* 17 | %6 = getelementptr { double, i64 }* %5, i32 0, i32 0 18 | %7 = load double* %6, align 1 19 | %8 = getelementptr { double, i64 }* %5, i32 0, i32 1 20 | %9 = load i64* %8, align 1 21 | call void @callee(double %7, i64 %9) 22 | ret void 23 | } 24 | -------------------------------------------------------------------------------- /test/x86_64/PassArrayStructDoubleIntLong.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: void ([1 x {double, int, long }]) 3 | 4 | declare void @callee([1 x { double, i32, i64 }]* byval align 8) 5 | 6 | define void @caller([1 x { double, i32, i64 }]* byval align 8) { 7 | %indirect.arg.mem = alloca [1 x { double, i32, i64 }], align 8 8 | %2 = load [1 x { double, i32, i64 }]* %0, align 8 9 | store [1 x { double, i32, i64 }] %2, [1 x { double, i32, i64 }]* %indirect.arg.mem, align 8 10 | call void @callee([1 x { double, i32, i64 }]* byval align 8 %indirect.arg.mem) 11 | ret void 12 | } 13 | -------------------------------------------------------------------------------- /test/x86_64/PassCharShortIntLongLongPtr.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: void (char, short, int, longlong, ptr) 3 | 4 | declare void @callee(i8 signext, i16 signext, i32, i64, i8*) 5 | 6 | define void @caller(i8 signext, i16 signext, i32, i64, i8*) { 7 | call void @callee(i8 signext %0, i16 signext %1, i32 %2, i64 %3, i8* %4) 8 | ret void 9 | } 10 | -------------------------------------------------------------------------------- /test/x86_64/PassIntStructInt.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: void (int, { int }) 3 | ; 4 | ; Check for valid coercion. The struct should be passed/returned as i32, not as 5 | ; i64 for better code quality. 6 | 7 | declare void @callee(i32, i32) 8 | 9 | define void @caller(i32, i32 %coerce) { 10 | %coerce.arg.source = alloca { i32 }, align 4 11 | %coerce.mem = alloca { i32 }, align 4 12 | %coerce.dive = getelementptr { i32 }* %coerce.mem, i32 0, i32 0 13 | store i32 %coerce, i32* %coerce.dive 14 | %2 = load { i32 }* %coerce.mem 15 | store { i32 } %2, { i32 }* %coerce.arg.source 16 | %coerce.dive1 = getelementptr { i32 }* %coerce.arg.source, i32 0, i32 0 17 | %3 = load i32* %coerce.dive1 18 | call void @callee(i32 %0, i32 %3) 19 | ret void 20 | } 21 | -------------------------------------------------------------------------------- /test/x86_64/PassIntStructShortUintInt.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: void (int, {short, uint, int}) 3 | 4 | declare void @callee(i32, i64, i32) 5 | 6 | define void @caller(i32, i64 %coerce0, i32 %coerce1) { 7 | %coerce.arg.source.coerce = alloca { i64, i32 } 8 | %coerce.arg.source = alloca { i16, i32, i32 }, align 4 9 | %coerce = alloca { i64, i32 }, align 8 10 | %coerce.mem = alloca { i16, i32, i32 }, align 8 11 | %2 = getelementptr { i64, i32 }* %coerce, i32 0, i32 0 12 | store i64 %coerce0, i64* %2 13 | %3 = getelementptr { i64, i32 }* %coerce, i32 0, i32 1 14 | store i32 %coerce1, i32* %3 15 | %4 = bitcast { i16, i32, i32 }* %coerce.mem to i8* 16 | %5 = bitcast { i64, i32 }* %coerce to i8* 17 | call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %4, i8* align 8 %5, i64 12, i1 false) 18 | %6 = load { i16, i32, i32 }* %coerce.mem 19 | store { i16, i32, i32 } %6, { i16, i32, i32 }* %coerce.arg.source 20 | %7 = bitcast { i64, i32 }* %coerce.arg.source.coerce to i8* 21 | %8 = bitcast { i16, i32, i32 }* %coerce.arg.source to i8* 22 | call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %7, i8* align 1 %8, i64 12, i1 false) 23 | %9 = getelementptr { i64, i32 }* %coerce.arg.source.coerce, i32 0, i32 0 24 | %10 = load i64* %9, align 1 25 | %11 = getelementptr { i64, i32 }* %coerce.arg.source.coerce, i32 0, i32 1 26 | %12 = load i32* %11, align 1 27 | call void @callee(i32 %0, i64 %10, i32 %12) 28 | ret void 29 | } 30 | 31 | ; Function Attrs: nounwind 32 | declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture readonly, i64, i32, i1) #0 33 | 34 | attributes #0 = { argmemonly nounwind } 35 | -------------------------------------------------------------------------------- /test/x86_64/PassLongLongArrayAndReturnLongLongArray.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: {[3 x longlong]} (int, int, int, int, {[2 x longlong]}, int) 3 | ; 4 | ; Check that sret parameter is accounted for when checking available integer registers. 5 | 6 | declare void @callee({ [3 x i64] }* noalias sret, i32, i32, i32, i32, { [2 x i64] }* byval align 8, i32) 7 | 8 | define void @caller({ [3 x i64] }* noalias sret %agg.result, i32, i32, i32, i32, { [2 x i64] }* byval align 8, i32) { 9 | %indirect.arg.mem = alloca { [2 x i64] }, align 8 10 | %7 = alloca { [3 x i64] }, align 8 11 | %8 = load { [2 x i64] }* %4, align 8 12 | store { [2 x i64] } %8, { [2 x i64] }* %indirect.arg.mem, align 8 13 | call void @callee({ [3 x i64] }* noalias sret %7, i32 %0, i32 %1, i32 %2, i32 %3, { [2 x i64] }* byval align 8 %indirect.arg.mem, i32 %5) 14 | %9 = load { [3 x i64] }* %7 15 | store { [3 x i64] } %9, { [3 x i64] }* %agg.result 16 | ret void 17 | } 18 | -------------------------------------------------------------------------------- /test/x86_64/PassNamedStruct1Int.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: void (struct NamedStruct{ int }) 3 | 4 | %NamedStruct = type { i32 } 5 | 6 | declare void @callee(i32) 7 | 8 | define void @caller(i32 %coerce) { 9 | %coerce.arg.source = alloca %NamedStruct, align 4 10 | %coerce.mem = alloca %NamedStruct, align 4 11 | %coerce.dive = getelementptr %NamedStruct* %coerce.mem, i32 0, i32 0 12 | store i32 %coerce, i32* %coerce.dive 13 | %1 = load %NamedStruct* %coerce.mem 14 | store %NamedStruct %1, %NamedStruct* %coerce.arg.source 15 | %coerce.dive1 = getelementptr %NamedStruct* %coerce.arg.source, i32 0, i32 0 16 | %2 = load i32* %coerce.dive1 17 | call void @callee(i32 %2) 18 | ret void 19 | } 20 | -------------------------------------------------------------------------------- /test/x86_64/PassNamedStruct2Ints.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: void (struct NamedStruct{ int, int }) 3 | 4 | %NamedStruct = type { i32, i32 } 5 | 6 | declare void @callee(i64) 7 | 8 | define void @caller(i64 %coerce) { 9 | %coerce.arg.source = alloca %NamedStruct, align 4 10 | %coerce.mem = alloca %NamedStruct, align 8 11 | %1 = bitcast %NamedStruct* %coerce.mem to i64* 12 | store i64 %coerce, i64* %1, align 1 13 | %2 = load %NamedStruct* %coerce.mem 14 | store %NamedStruct %2, %NamedStruct* %coerce.arg.source 15 | %3 = bitcast %NamedStruct* %coerce.arg.source to i64* 16 | %4 = load i64* %3, align 1 17 | call void @callee(i64 %4) 18 | ret void 19 | } 20 | -------------------------------------------------------------------------------- /test/x86_64/PassNamedStructPtrInt.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: void (struct NamedStruct{ ptr, int }) 3 | 4 | %NamedStruct = type { i8*, i32 } 5 | 6 | declare void @callee(i8*, i32) 7 | 8 | define void @caller(i8* %coerce0, i32 %coerce1) { 9 | %coerce.arg.source = alloca %NamedStruct, align 8 10 | %coerce.mem = alloca %NamedStruct, align 8 11 | %1 = getelementptr %NamedStruct* %coerce.mem, i32 0, i32 0 12 | store i8* %coerce0, i8** %1 13 | %2 = getelementptr %NamedStruct* %coerce.mem, i32 0, i32 1 14 | store i32 %coerce1, i32* %2 15 | %3 = load %NamedStruct* %coerce.mem 16 | store %NamedStruct %3, %NamedStruct* %coerce.arg.source 17 | %4 = getelementptr %NamedStruct* %coerce.arg.source, i32 0, i32 0 18 | %5 = load i8** %4, align 1 19 | %6 = getelementptr %NamedStruct* %coerce.arg.source, i32 0, i32 1 20 | %7 = load i32* %6, align 1 21 | call void @callee(i8* %5, i32 %7) 22 | ret void 23 | } 24 | -------------------------------------------------------------------------------- /test/x86_64/PassNamedUnion1Int.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: void (union NamedUnion{ int }) 3 | 4 | %NamedUnion = type { i32 } 5 | 6 | declare void @callee(i32) 7 | 8 | define void @caller(i32 %coerce) { 9 | %coerce.arg.source = alloca %NamedUnion, align 4 10 | %coerce.mem = alloca %NamedUnion, align 4 11 | %1 = bitcast %NamedUnion* %coerce.mem to i32* 12 | store i32 %coerce, i32* %1, align 1 13 | %2 = load %NamedUnion* %coerce.mem 14 | store %NamedUnion %2, %NamedUnion* %coerce.arg.source 15 | %3 = bitcast %NamedUnion* %coerce.arg.source to i32* 16 | %4 = load i32* %3, align 1 17 | call void @callee(i32 %4) 18 | ret void 19 | } 20 | -------------------------------------------------------------------------------- /test/x86_64/PassStruct1Float.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: void ({ float }) 3 | 4 | declare void @callee(float) 5 | 6 | define void @caller(float %coerce) { 7 | %coerce.arg.source = alloca { float }, align 4 8 | %coerce.mem = alloca { float }, align 4 9 | %coerce.dive = getelementptr { float }* %coerce.mem, i32 0, i32 0 10 | store float %coerce, float* %coerce.dive, align 1 11 | %1 = load { float }* %coerce.mem 12 | store { float } %1, { float }* %coerce.arg.source 13 | %coerce.dive1 = getelementptr { float }* %coerce.arg.source, i32 0, i32 0 14 | %2 = load float* %coerce.dive1, align 1 15 | call void @callee(float %2) 16 | ret void 17 | } 18 | -------------------------------------------------------------------------------- /test/x86_64/PassStruct1Int.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: void ({ int }) 3 | 4 | declare void @callee(i32) 5 | 6 | define void @caller(i32 %coerce) { 7 | %coerce.arg.source = alloca { i32 }, align 4 8 | %coerce.mem = alloca { i32 }, align 4 9 | %coerce.dive = getelementptr { i32 }* %coerce.mem, i32 0, i32 0 10 | store i32 %coerce, i32* %coerce.dive 11 | %1 = load { i32 }* %coerce.mem 12 | store { i32 } %1, { i32 }* %coerce.arg.source 13 | %coerce.dive1 = getelementptr { i32 }* %coerce.arg.source, i32 0, i32 0 14 | %2 = load i32* %coerce.dive1 15 | call void @callee(i32 %2) 16 | ret void 17 | } 18 | -------------------------------------------------------------------------------- /test/x86_64/PassStruct2Floats.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: void ({ float, float }) 3 | 4 | declare void @callee(<2 x float>) 5 | 6 | define void @caller(<2 x float> %coerce) { 7 | %coerce.arg.source = alloca { float, float }, align 4 8 | %coerce.mem = alloca { float, float }, align 4 9 | %1 = bitcast { float, float }* %coerce.mem to <2 x float>* 10 | store <2 x float> %coerce, <2 x float>* %1, align 1 11 | %2 = load { float, float }* %coerce.mem 12 | store { float, float } %2, { float, float }* %coerce.arg.source 13 | %3 = bitcast { float, float }* %coerce.arg.source to <2 x float>* 14 | %4 = load <2 x float>* %3, align 1 15 | call void @callee(<2 x float> %4) 16 | ret void 17 | } 18 | -------------------------------------------------------------------------------- /test/x86_64/PassStruct2Ints.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: void ({ int, int }) 3 | 4 | declare void @callee(i64) 5 | 6 | define void @caller(i64 %coerce) { 7 | %coerce.arg.source = alloca { i32, i32 }, align 4 8 | %coerce.mem = alloca { i32, i32 }, align 8 9 | %1 = bitcast { i32, i32 }* %coerce.mem to i64* 10 | store i64 %coerce, i64* %1, align 1 11 | %2 = load { i32, i32 }* %coerce.mem 12 | store { i32, i32 } %2, { i32, i32 }* %coerce.arg.source 13 | %3 = bitcast { i32, i32 }* %coerce.arg.source to i64* 14 | %4 = load i64* %3, align 1 15 | call void @callee(i64 %4) 16 | ret void 17 | } 18 | -------------------------------------------------------------------------------- /test/x86_64/PassStruct3Ints.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: void ({ int, int, int }) 3 | 4 | declare void @callee(i64, i32) 5 | 6 | define void @caller(i64 %coerce0, i32 %coerce1) { 7 | %coerce.arg.source.coerce = alloca { i64, i32 } 8 | %coerce.arg.source = alloca { i32, i32, i32 }, align 4 9 | %coerce = alloca { i64, i32 }, align 8 10 | %coerce.mem = alloca { i32, i32, i32 }, align 8 11 | %1 = getelementptr { i64, i32 }* %coerce, i32 0, i32 0 12 | store i64 %coerce0, i64* %1 13 | %2 = getelementptr { i64, i32 }* %coerce, i32 0, i32 1 14 | store i32 %coerce1, i32* %2 15 | %3 = bitcast { i32, i32, i32 }* %coerce.mem to i8* 16 | %4 = bitcast { i64, i32 }* %coerce to i8* 17 | call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %3, i8* align 8 %4, i64 12, i1 false) 18 | %5 = load { i32, i32, i32 }* %coerce.mem 19 | store { i32, i32, i32 } %5, { i32, i32, i32 }* %coerce.arg.source 20 | %6 = bitcast { i64, i32 }* %coerce.arg.source.coerce to i8* 21 | %7 = bitcast { i32, i32, i32 }* %coerce.arg.source to i8* 22 | call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %6, i8* align 1 %7, i64 12, i1 false) 23 | %8 = getelementptr { i64, i32 }* %coerce.arg.source.coerce, i32 0, i32 0 24 | %9 = load i64* %8, align 1 25 | %10 = getelementptr { i64, i32 }* %coerce.arg.source.coerce, i32 0, i32 1 26 | %11 = load i32* %10, align 1 27 | call void @callee(i64 %9, i32 %11) 28 | ret void 29 | } 30 | 31 | ; Function Attrs: nounwind 32 | declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture readonly, i64, i32, i1) #0 33 | 34 | attributes #0 = { argmemonly nounwind } 35 | -------------------------------------------------------------------------------- /test/x86_64/PassStruct4Ints.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: void ({ int, int, int, int }) 3 | 4 | declare void @callee(i64, i64) 5 | 6 | define void @caller(i64 %coerce0, i64 %coerce1) { 7 | %coerce.arg.source = alloca { i32, i32, i32, i32 }, align 4 8 | %coerce.mem = alloca { i32, i32, i32, i32 }, align 8 9 | %1 = bitcast { i32, i32, i32, i32 }* %coerce.mem to { i64, i64 }* 10 | %2 = getelementptr { i64, i64 }* %1, i32 0, i32 0 11 | store i64 %coerce0, i64* %2 12 | %3 = getelementptr { i64, i64 }* %1, i32 0, i32 1 13 | store i64 %coerce1, i64* %3 14 | %4 = load { i32, i32, i32, i32 }* %coerce.mem 15 | store { i32, i32, i32, i32 } %4, { i32, i32, i32, i32 }* %coerce.arg.source 16 | %5 = bitcast { i32, i32, i32, i32 }* %coerce.arg.source to { i64, i64 }* 17 | %6 = getelementptr { i64, i64 }* %5, i32 0, i32 0 18 | %7 = load i64* %6, align 1 19 | %8 = getelementptr { i64, i64 }* %5, i32 0, i32 1 20 | %9 = load i64* %8, align 1 21 | call void @callee(i64 %7, i64 %9) 22 | ret void 23 | } 24 | -------------------------------------------------------------------------------- /test/x86_64/PassStruct5Ints.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: void ({ int, int, int, int, int }) 3 | 4 | declare void @callee({ i32, i32, i32, i32, i32 }* byval align 8) 5 | 6 | define void @caller({ i32, i32, i32, i32, i32 }* byval align 8) { 7 | %indirect.arg.mem = alloca { i32, i32, i32, i32, i32 }, align 8 8 | %2 = load { i32, i32, i32, i32, i32 }* %0, align 8 9 | store { i32, i32, i32, i32, i32 } %2, { i32, i32, i32, i32, i32 }* %indirect.arg.mem, align 8 10 | call void @callee({ i32, i32, i32, i32, i32 }* byval align 8 %indirect.arg.mem) 11 | ret void 12 | } 13 | -------------------------------------------------------------------------------- /test/x86_64/PassStructArray1Char3Chars.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: void ({[8 x char], char, char, char}) 3 | 4 | declare void @callee(i64, i24) 5 | 6 | define void @caller(i64 %coerce0, i24 %coerce1) { 7 | %coerce.arg.source.coerce = alloca { i64, i24 } 8 | %coerce.arg.source = alloca { [8 x i8], i8, i8, i8 }, align 1 9 | %coerce = alloca { i64, i24 }, align 8 10 | %coerce.mem = alloca { [8 x i8], i8, i8, i8 }, align 8 11 | %1 = getelementptr { i64, i24 }* %coerce, i32 0, i32 0 12 | store i64 %coerce0, i64* %1 13 | %2 = getelementptr { i64, i24 }* %coerce, i32 0, i32 1 14 | store i24 %coerce1, i24* %2 15 | %3 = bitcast { [8 x i8], i8, i8, i8 }* %coerce.mem to i8* 16 | %4 = bitcast { i64, i24 }* %coerce to i8* 17 | call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %3, i8* align 8 %4, i64 11, i1 false) 18 | %5 = load { [8 x i8], i8, i8, i8 }* %coerce.mem 19 | store { [8 x i8], i8, i8, i8 } %5, { [8 x i8], i8, i8, i8 }* %coerce.arg.source 20 | %6 = bitcast { i64, i24 }* %coerce.arg.source.coerce to i8* 21 | %7 = bitcast { [8 x i8], i8, i8, i8 }* %coerce.arg.source to i8* 22 | call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %6, i8* align 1 %7, i64 11, i1 false) 23 | %8 = getelementptr { i64, i24 }* %coerce.arg.source.coerce, i32 0, i32 0 24 | %9 = load i64* %8, align 1 25 | %10 = getelementptr { i64, i24 }* %coerce.arg.source.coerce, i32 0, i32 1 26 | %11 = load i24* %10, align 1 27 | call void @callee(i64 %9, i24 %11) 28 | ret void 29 | } 30 | 31 | ; Function Attrs: nounwind 32 | declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture readonly, i64, i32, i1) #0 33 | 34 | attributes #0 = { argmemonly nounwind } 35 | -------------------------------------------------------------------------------- /test/x86_64/PassStructArrayVector4FloatsAndReturnStructArrayVector4Floats.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: {[1 x <4 x float>]} ({[1 x <4 x float>]}) 3 | 4 | declare <4 x float> @callee(<4 x float>) 5 | 6 | define <4 x float> @caller(<4 x float> %coerce) { 7 | %coerce4 = alloca { [1 x <4 x float>] }, align 16 8 | %coerce2 = alloca { [1 x <4 x float>] }, align 16 9 | %coerce.arg.source = alloca { [1 x <4 x float>] }, align 16 10 | %coerce.mem = alloca { [1 x <4 x float>] }, align 16 11 | %coerce.dive = getelementptr { [1 x <4 x float>] }* %coerce.mem, i32 0, i32 0 12 | %1 = bitcast [1 x <4 x float>]* %coerce.dive to <4 x float>* 13 | store <4 x float> %coerce, <4 x float>* %1, align 1 14 | %2 = load { [1 x <4 x float>] }* %coerce.mem 15 | store { [1 x <4 x float>] } %2, { [1 x <4 x float>] }* %coerce.arg.source 16 | %coerce.dive1 = getelementptr { [1 x <4 x float>] }* %coerce.arg.source, i32 0, i32 0 17 | %3 = bitcast [1 x <4 x float>]* %coerce.dive1 to <4 x float>* 18 | %4 = load <4 x float>* %3, align 1 19 | %5 = call <4 x float> @callee(<4 x float> %4) 20 | %coerce.dive3 = getelementptr { [1 x <4 x float>] }* %coerce2, i32 0, i32 0 21 | %6 = bitcast [1 x <4 x float>]* %coerce.dive3 to <4 x float>* 22 | store <4 x float> %5, <4 x float>* %6, align 1 23 | %7 = load { [1 x <4 x float>] }* %coerce2, align 16 24 | store { [1 x <4 x float>] } %7, { [1 x <4 x float>] }* %coerce4, align 16 25 | %coerce.dive5 = getelementptr { [1 x <4 x float>] }* %coerce4, i32 0, i32 0 26 | %8 = bitcast [1 x <4 x float>]* %coerce.dive5 to <4 x float>* 27 | %9 = load <4 x float>* %8, align 1 28 | ret <4 x float> %9 29 | } 30 | -------------------------------------------------------------------------------- /test/x86_64/PassStructDoubleInt.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: void ({ double, int }) 3 | 4 | declare void @callee(double, i32) 5 | 6 | define void @caller(double %coerce0, i32 %coerce1) { 7 | %coerce.arg.source = alloca { double, i32 }, align 8 8 | %coerce.mem = alloca { double, i32 }, align 8 9 | %1 = getelementptr { double, i32 }* %coerce.mem, i32 0, i32 0 10 | store double %coerce0, double* %1 11 | %2 = getelementptr { double, i32 }* %coerce.mem, i32 0, i32 1 12 | store i32 %coerce1, i32* %2 13 | %3 = load { double, i32 }* %coerce.mem 14 | store { double, i32 } %3, { double, i32 }* %coerce.arg.source 15 | %4 = getelementptr { double, i32 }* %coerce.arg.source, i32 0, i32 0 16 | %5 = load double* %4, align 1 17 | %6 = getelementptr { double, i32 }* %coerce.arg.source, i32 0, i32 1 18 | %7 = load i32* %6, align 1 19 | call void @callee(double %5, i32 %7) 20 | ret void 21 | } 22 | -------------------------------------------------------------------------------- /test/x86_64/PassStructLongDouble.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: void ({ longdouble }) 3 | ; 4 | ; Check byval alignment. 5 | 6 | declare void @callee({ x86_fp80 }* byval align 16) 7 | 8 | define void @caller({ x86_fp80 }* byval align 16) { 9 | %indirect.arg.mem = alloca { x86_fp80 }, align 16 10 | %2 = load { x86_fp80 }* %0, align 16 11 | store { x86_fp80 } %2, { x86_fp80 }* %indirect.arg.mem, align 16 12 | call void @callee({ x86_fp80 }* byval align 16 %indirect.arg.mem) 13 | ret void 14 | } 15 | -------------------------------------------------------------------------------- /test/x86_64/PassStructLongDoubleLongDouble.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: void ({ longdouble, longdouble }) 3 | 4 | declare void @callee({ x86_fp80, x86_fp80 }* byval align 16) 5 | 6 | define void @caller({ x86_fp80, x86_fp80 }* byval align 16) { 7 | %indirect.arg.mem = alloca { x86_fp80, x86_fp80 }, align 16 8 | %2 = load { x86_fp80, x86_fp80 }* %0, align 16 9 | store { x86_fp80, x86_fp80 } %2, { x86_fp80, x86_fp80 }* %indirect.arg.mem, align 16 10 | call void @callee({ x86_fp80, x86_fp80 }* byval align 16 %indirect.arg.mem) 11 | ret void 12 | } 13 | -------------------------------------------------------------------------------- /test/x86_64/PassStructLongPtr.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: void ({ long, ptr }) 3 | 4 | declare void @callee(i64, i8*) 5 | 6 | define void @caller(i64 %coerce0, i8* %coerce1) { 7 | %coerce.arg.source = alloca { i64, i8* }, align 8 8 | %coerce.mem = alloca { i64, i8* }, align 8 9 | %1 = getelementptr { i64, i8* }* %coerce.mem, i32 0, i32 0 10 | store i64 %coerce0, i64* %1 11 | %2 = getelementptr { i64, i8* }* %coerce.mem, i32 0, i32 1 12 | store i8* %coerce1, i8** %2 13 | %3 = load { i64, i8* }* %coerce.mem 14 | store { i64, i8* } %3, { i64, i8* }* %coerce.arg.source 15 | %4 = getelementptr { i64, i8* }* %coerce.arg.source, i32 0, i32 0 16 | %5 = load i64* %4, align 1 17 | %6 = getelementptr { i64, i8* }* %coerce.arg.source, i32 0, i32 1 18 | %7 = load i8** %6, align 1 19 | call void @callee(i64 %5, i8* %7) 20 | ret void 21 | } 22 | -------------------------------------------------------------------------------- /test/x86_64/PassStructLongPtrAndReturnPtr.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: ptr ({ long, ptr }) 3 | 4 | declare i8* @callee(i64, i8*) 5 | 6 | define i8* @caller(i64 %coerce0, i8* %coerce1) { 7 | %coerce.arg.source = alloca { i64, i8* }, align 8 8 | %coerce.mem = alloca { i64, i8* }, align 8 9 | %1 = getelementptr { i64, i8* }* %coerce.mem, i32 0, i32 0 10 | store i64 %coerce0, i64* %1 11 | %2 = getelementptr { i64, i8* }* %coerce.mem, i32 0, i32 1 12 | store i8* %coerce1, i8** %2 13 | %3 = load { i64, i8* }* %coerce.mem 14 | store { i64, i8* } %3, { i64, i8* }* %coerce.arg.source 15 | %4 = getelementptr { i64, i8* }* %coerce.arg.source, i32 0, i32 0 16 | %5 = load i64* %4, align 1 17 | %6 = getelementptr { i64, i8* }* %coerce.arg.source, i32 0, i32 1 18 | %7 = load i8** %6, align 1 19 | %8 = call i8* @callee(i64 %5, i8* %7) 20 | ret i8* %8 21 | } 22 | -------------------------------------------------------------------------------- /test/x86_64/PassStructVector4FloatsAndReturnStructVector4Floats.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: {<4 x float>} ({<4 x float>}) 3 | 4 | declare <4 x float> @callee(<4 x float>) 5 | 6 | define <4 x float> @caller(<4 x float> %coerce) { 7 | %coerce4 = alloca { <4 x float> }, align 16 8 | %coerce2 = alloca { <4 x float> }, align 16 9 | %coerce.arg.source = alloca { <4 x float> }, align 16 10 | %coerce.mem = alloca { <4 x float> }, align 16 11 | %coerce.dive = getelementptr { <4 x float> }* %coerce.mem, i32 0, i32 0 12 | store <4 x float> %coerce, <4 x float>* %coerce.dive, align 1 13 | %1 = load { <4 x float> }* %coerce.mem 14 | store { <4 x float> } %1, { <4 x float> }* %coerce.arg.source 15 | %coerce.dive1 = getelementptr { <4 x float> }* %coerce.arg.source, i32 0, i32 0 16 | %2 = load <4 x float>* %coerce.dive1, align 1 17 | %3 = call <4 x float> @callee(<4 x float> %2) 18 | %coerce.dive3 = getelementptr { <4 x float> }* %coerce2, i32 0, i32 0 19 | store <4 x float> %3, <4 x float>* %coerce.dive3, align 1 20 | %4 = load { <4 x float> }* %coerce2, align 16 21 | store { <4 x float> } %4, { <4 x float> }* %coerce4, align 16 22 | %coerce.dive5 = getelementptr { <4 x float> }* %coerce4, i32 0, i32 0 23 | %5 = load <4 x float>* %coerce.dive5, align 1 24 | ret <4 x float> %5 25 | } 26 | -------------------------------------------------------------------------------- /test/x86_64/PassUnionArray5IntsFloat.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: void (union{ [5 x int], float }) 3 | 4 | declare void @callee({ [5 x i32] }* byval align 8) 5 | 6 | define void @caller({ [5 x i32] }* byval align 8) { 7 | %indirect.arg.mem = alloca { [5 x i32] }, align 8 8 | %2 = load { [5 x i32] }* %0, align 8 9 | store { [5 x i32] } %2, { [5 x i32] }* %indirect.arg.mem, align 8 10 | call void @callee({ [5 x i32] }* byval align 8 %indirect.arg.mem) 11 | ret void 12 | } 13 | -------------------------------------------------------------------------------- /test/x86_64/PassUnionDoubleInt.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: void (union{ double, int }) 3 | 4 | declare void @callee(i64) 5 | 6 | define void @caller(i64 %coerce) { 7 | %coerce.arg.source = alloca { double }, align 8 8 | %coerce.mem = alloca { double }, align 8 9 | %1 = bitcast { double }* %coerce.mem to i64* 10 | store i64 %coerce, i64* %1, align 1 11 | %2 = load { double }* %coerce.mem 12 | store { double } %2, { double }* %coerce.arg.source 13 | %3 = bitcast { double }* %coerce.arg.source to i64* 14 | %4 = load i64* %3, align 1 15 | call void @callee(i64 %4) 16 | ret void 17 | } 18 | -------------------------------------------------------------------------------- /test/x86_64/PassVector4FloatsAndReturnVector4Floats.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: <4 x float> (<4 x float>) 3 | 4 | declare <4 x float> @callee(<4 x float>) 5 | 6 | define <4 x float> @caller(<4 x float>) { 7 | %2 = call <4 x float> @callee(<4 x float> %0) 8 | ret <4 x float> %2 9 | } 10 | -------------------------------------------------------------------------------- /test/x86_64/ReturnChar.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: char () 3 | 4 | declare signext i8 @callee() 5 | 6 | define signext i8 @caller() { 7 | %1 = call signext i8 @callee() 8 | ret i8 %1 9 | } 10 | -------------------------------------------------------------------------------- /test/x86_64/ReturnDouble.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: double () 3 | 4 | declare double @callee() 5 | 6 | define double @caller() { 7 | %1 = call double @callee() 8 | ret double %1 9 | } 10 | -------------------------------------------------------------------------------- /test/x86_64/ReturnFloat.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: float () 3 | 4 | declare float @callee() 5 | 6 | define float @caller() { 7 | %1 = call float @callee() 8 | ret float %1 9 | } 10 | -------------------------------------------------------------------------------- /test/x86_64/ReturnInt.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: int () 3 | 4 | declare i32 @callee() 5 | 6 | define i32 @caller() { 7 | %1 = call i32 @callee() 8 | ret i32 %1 9 | } 10 | -------------------------------------------------------------------------------- /test/x86_64/ReturnLongDouble.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: longdouble () 3 | 4 | declare x86_fp80 @callee() 5 | 6 | define x86_fp80 @caller() { 7 | %1 = call x86_fp80 @callee() 8 | ret x86_fp80 %1 9 | } 10 | -------------------------------------------------------------------------------- /test/x86_64/ReturnSChar.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: schar () 3 | 4 | declare signext i8 @callee() 5 | 6 | define signext i8 @caller() { 7 | %1 = call signext i8 @callee() 8 | ret i8 %1 9 | } 10 | -------------------------------------------------------------------------------- /test/x86_64/ReturnShort.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: short () 3 | 4 | declare signext i16 @callee() 5 | 6 | define signext i16 @caller() { 7 | %1 = call signext i16 @callee() 8 | ret i16 %1 9 | } 10 | -------------------------------------------------------------------------------- /test/x86_64/ReturnStruct1Float.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: {float} () 3 | 4 | declare float @callee() 5 | 6 | define float @caller() { 7 | %coerce1 = alloca { float }, align 4 8 | %coerce = alloca { float }, align 4 9 | %1 = call float @callee() 10 | %coerce.dive = getelementptr { float }* %coerce, i32 0, i32 0 11 | store float %1, float* %coerce.dive, align 1 12 | %2 = load { float }* %coerce, align 4 13 | store { float } %2, { float }* %coerce1, align 4 14 | %coerce.dive2 = getelementptr { float }* %coerce1, i32 0, i32 0 15 | %3 = load float* %coerce.dive2, align 1 16 | ret float %3 17 | } 18 | -------------------------------------------------------------------------------- /test/x86_64/ReturnStruct1Int.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: {int} () 3 | 4 | declare i32 @callee() 5 | 6 | define i32 @caller() { 7 | %coerce1 = alloca { i32 }, align 4 8 | %coerce = alloca { i32 }, align 4 9 | %1 = call i32 @callee() 10 | %coerce.dive = getelementptr { i32 }* %coerce, i32 0, i32 0 11 | store i32 %1, i32* %coerce.dive 12 | %2 = load { i32 }* %coerce, align 4 13 | store { i32 } %2, { i32 }* %coerce1, align 4 14 | %coerce.dive2 = getelementptr { i32 }* %coerce1, i32 0, i32 0 15 | %3 = load i32* %coerce.dive2 16 | ret i32 %3 17 | } 18 | -------------------------------------------------------------------------------- /test/x86_64/ReturnStruct2Floats.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: {float, float} () 3 | 4 | declare <2 x float> @callee() 5 | 6 | define <2 x float> @caller() { 7 | %coerce1 = alloca { float, float }, align 4 8 | %coerce = alloca { float, float }, align 4 9 | %1 = call <2 x float> @callee() 10 | %2 = bitcast { float, float }* %coerce to <2 x float>* 11 | store <2 x float> %1, <2 x float>* %2, align 1 12 | %3 = load { float, float }* %coerce, align 4 13 | store { float, float } %3, { float, float }* %coerce1, align 4 14 | %4 = bitcast { float, float }* %coerce1 to <2 x float>* 15 | %5 = load <2 x float>* %4, align 1 16 | ret <2 x float> %5 17 | } 18 | -------------------------------------------------------------------------------- /test/x86_64/ReturnStruct2Ints.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: {int, int} () 3 | 4 | declare i64 @callee() 5 | 6 | define i64 @caller() { 7 | %coerce1 = alloca { i32, i32 }, align 4 8 | %coerce = alloca { i32, i32 }, align 4 9 | %1 = call i64 @callee() 10 | %2 = bitcast { i32, i32 }* %coerce to i64* 11 | store i64 %1, i64* %2, align 1 12 | %3 = load { i32, i32 }* %coerce, align 4 13 | store { i32, i32 } %3, { i32, i32 }* %coerce1, align 4 14 | %4 = bitcast { i32, i32 }* %coerce1 to i64* 15 | %5 = load i64* %4, align 1 16 | ret i64 %5 17 | } 18 | -------------------------------------------------------------------------------- /test/x86_64/ReturnStruct2Ptrs.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: {ptr, ptr} () 3 | 4 | declare { i8*, i8* } @callee() 5 | 6 | define { i8*, i8* } @caller() { 7 | %agg.tmp = alloca { i8*, i8* }, align 8 8 | %1 = call { i8*, i8* } @callee() 9 | %2 = getelementptr { i8*, i8* }* %agg.tmp, i32 0, i32 0 10 | %3 = extractvalue { i8*, i8* } %1, 0 11 | store i8* %3, i8** %2 12 | %4 = getelementptr { i8*, i8* }* %agg.tmp, i32 0, i32 1 13 | %5 = extractvalue { i8*, i8* } %1, 1 14 | store i8* %5, i8** %4 15 | %6 = load { i8*, i8* }* %agg.tmp, align 8 16 | ret { i8*, i8* } %6 17 | } 18 | -------------------------------------------------------------------------------- /test/x86_64/ReturnStruct3Ints.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: {int, int, int} () 3 | 4 | declare { i64, i32 } @callee() 5 | 6 | define { i64, i32 } @caller() { 7 | %coerce.mem.load = alloca { i64, i32 } 8 | %coerce1 = alloca { i32, i32, i32 }, align 4 9 | %coerce.mem.store = alloca { i64, i32 } 10 | %coerce = alloca { i32, i32, i32 }, align 4 11 | %1 = call { i64, i32 } @callee() 12 | store { i64, i32 } %1, { i64, i32 }* %coerce.mem.store 13 | %2 = bitcast { i64, i32 }* %coerce.mem.store to i8* 14 | %3 = bitcast { i32, i32, i32 }* %coerce to i8* 15 | call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %3, i8* align 1 %2, i64 12, i1 false) 16 | %4 = load { i32, i32, i32 }* %coerce, align 4 17 | store { i32, i32, i32 } %4, { i32, i32, i32 }* %coerce1, align 4 18 | %5 = bitcast { i64, i32 }* %coerce.mem.load to i8* 19 | %6 = bitcast { i32, i32, i32 }* %coerce1 to i8* 20 | call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %5, i8* align 1 %6, i64 12, i1 false) 21 | %7 = load { i64, i32 }* %coerce.mem.load 22 | ret { i64, i32 } %7 23 | } 24 | 25 | ; Function Attrs: nounwind 26 | declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture readonly, i64, i32, i1) #0 27 | 28 | attributes #0 = { argmemonly nounwind } 29 | -------------------------------------------------------------------------------- /test/x86_64/ReturnStruct4Ints.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: {int, int, int, int} () 3 | 4 | declare { i64, i64 } @callee() 5 | 6 | define { i64, i64 } @caller() { 7 | %coerce1 = alloca { i32, i32, i32, i32 }, align 4 8 | %coerce = alloca { i32, i32, i32, i32 }, align 4 9 | %1 = call { i64, i64 } @callee() 10 | %2 = bitcast { i32, i32, i32, i32 }* %coerce to { i64, i64 }* 11 | %3 = getelementptr { i64, i64 }* %2, i32 0, i32 0 12 | %4 = extractvalue { i64, i64 } %1, 0 13 | store i64 %4, i64* %3, align 1 14 | %5 = getelementptr { i64, i64 }* %2, i32 0, i32 1 15 | %6 = extractvalue { i64, i64 } %1, 1 16 | store i64 %6, i64* %5, align 1 17 | %7 = load { i32, i32, i32, i32 }* %coerce, align 4 18 | store { i32, i32, i32, i32 } %7, { i32, i32, i32, i32 }* %coerce1, align 4 19 | %8 = bitcast { i32, i32, i32, i32 }* %coerce1 to { i64, i64 }* 20 | %9 = load { i64, i64 }* %8, align 1 21 | ret { i64, i64 } %9 22 | } 23 | -------------------------------------------------------------------------------- /test/x86_64/ReturnStruct5Ints.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: {int, int, int, int, int} () 3 | 4 | declare void @callee({ i32, i32, i32, i32, i32 }* noalias sret) 5 | 6 | define void @caller({ i32, i32, i32, i32, i32 }* noalias sret %agg.result) { 7 | %1 = alloca { i32, i32, i32, i32, i32 }, align 4 8 | call void @callee({ i32, i32, i32, i32, i32 }* noalias sret %1) 9 | %2 = load { i32, i32, i32, i32, i32 }* %1 10 | store { i32, i32, i32, i32, i32 } %2, { i32, i32, i32, i32, i32 }* %agg.result 11 | ret void 12 | } 13 | -------------------------------------------------------------------------------- /test/x86_64/ReturnStructEmptyArrayFloat.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: {[0 x char], float} () 3 | 4 | declare float @callee() 5 | 6 | define float @caller() { 7 | %coerce1 = alloca { [0 x i8], float }, align 4 8 | %coerce = alloca { [0 x i8], float }, align 4 9 | %1 = call float @callee() 10 | %2 = bitcast { [0 x i8], float }* %coerce to float* 11 | store float %1, float* %2, align 1 12 | %3 = load { [0 x i8], float }* %coerce, align 4 13 | store { [0 x i8], float } %3, { [0 x i8], float }* %coerce1, align 4 14 | %4 = bitcast { [0 x i8], float }* %coerce1 to float* 15 | %5 = load float* %4, align 1 16 | ret float %5 17 | } 18 | -------------------------------------------------------------------------------- /test/x86_64/ReturnStructFloatUnionEmpty.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: {float, union{}} () 3 | 4 | declare float @callee() 5 | 6 | define float @caller() { 7 | %coerce1 = alloca { float, {} }, align 4 8 | %coerce = alloca { float, {} }, align 4 9 | %1 = call float @callee() 10 | %coerce.dive = getelementptr { float, {} }* %coerce, i32 0, i32 0 11 | store float %1, float* %coerce.dive, align 1 12 | %2 = load { float, {} }* %coerce, align 4 13 | store { float, {} } %2, { float, {} }* %coerce1, align 4 14 | %coerce.dive2 = getelementptr { float, {} }* %coerce1, i32 0, i32 0 15 | %3 = load float* %coerce.dive2, align 1 16 | ret float %3 17 | } 18 | -------------------------------------------------------------------------------- /test/x86_64/ReturnStructLongInt.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: {long, int} () 3 | 4 | declare { i64, i32 } @callee() 5 | 6 | define { i64, i32 } @caller() { 7 | %agg.tmp = alloca { i64, i32 }, align 8 8 | %1 = call { i64, i32 } @callee() 9 | %2 = getelementptr { i64, i32 }* %agg.tmp, i32 0, i32 0 10 | %3 = extractvalue { i64, i32 } %1, 0 11 | store i64 %3, i64* %2 12 | %4 = getelementptr { i64, i32 }* %agg.tmp, i32 0, i32 1 13 | %5 = extractvalue { i64, i32 } %1, 1 14 | store i32 %5, i32* %4 15 | %6 = load { i64, i32 }* %agg.tmp, align 8 16 | ret { i64, i32 } %6 17 | } 18 | -------------------------------------------------------------------------------- /test/x86_64/ReturnUChar.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: uchar () 3 | 4 | declare zeroext i8 @callee() 5 | 6 | define zeroext i8 @caller() { 7 | %1 = call zeroext i8 @callee() 8 | ret i8 %1 9 | } 10 | -------------------------------------------------------------------------------- /test/x86_64/ReturnUShort.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: ushort () 3 | 4 | declare zeroext i16 @callee() 5 | 6 | define zeroext i16 @caller() { 7 | %1 = call zeroext i16 @callee() 8 | ret i16 %1 9 | } 10 | -------------------------------------------------------------------------------- /test/x86_64/ReturnUnionLongDoubleInt.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: union{longdouble, int} () 3 | 4 | declare void @callee({ x86_fp80 }* noalias sret) 5 | 6 | define void @caller({ x86_fp80 }* noalias sret %agg.result) { 7 | %1 = alloca { x86_fp80 }, align 16 8 | call void @callee({ x86_fp80 }* noalias sret %1) 9 | %2 = load { x86_fp80 }* %1 10 | store { x86_fp80 } %2, { x86_fp80 }* %agg.result 11 | ret void 12 | } 13 | -------------------------------------------------------------------------------- /test/x86_64/VarArgsPassIntVACharShortIntFloatDouble.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: void (int, ...(char, short, int, float, double)) 3 | 4 | declare void @callee(i32, ...) 5 | 6 | define void @caller(i32, i8 signext, i16 signext, i32, float, double) { 7 | %7 = sext i8 %1 to i32 8 | %8 = sext i16 %2 to i32 9 | %9 = fpext float %4 to double 10 | call void (i32, ...)* @callee(i32 %0, i32 %7, i32 %8, i32 %3, double %9, double %5) 11 | ret void 12 | } 13 | -------------------------------------------------------------------------------- /test/x86_64/VarArgsPassIntVAInt.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: void (int, ...(int)) 3 | 4 | declare void @callee(i32, ...) 5 | 6 | define void @caller(i32, i32) { 7 | call void (i32, ...)* @callee(i32 %0, i32 %1) 8 | ret void 9 | } 10 | -------------------------------------------------------------------------------- /test/x86_64/VarArgsPassIntVANone.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: void (int, ...()) 3 | 4 | declare void @callee(i32, ...) 5 | 6 | define void @caller(i32) { 7 | call void (i32, ...)* @callee(i32 %0) 8 | ret void 9 | } 10 | -------------------------------------------------------------------------------- /test/x86_64/VarArgsPassIntVAUnionLongDoubleCharLong.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: void (int, ...(union { longdouble, char, long })) 3 | 4 | declare void @callee(i32, ...) 5 | 6 | define void @caller(i32, { x86_fp80 }* byval align 16) { 7 | %indirect.arg.mem = alloca { x86_fp80 }, align 16 8 | %3 = load { x86_fp80 }* %1, align 16 9 | store { x86_fp80 } %3, { x86_fp80 }* %indirect.arg.mem, align 16 10 | call void (i32, ...)* @callee(i32 %0, { x86_fp80 }* byval align 16 %indirect.arg.mem) 11 | ret void 12 | } 13 | -------------------------------------------------------------------------------- /test/x86_64/VarArgsPassPtrVAPtrIntDouble.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: void (ptr, ...(ptr, int, double)) 3 | 4 | declare void @callee(i8*, ...) 5 | 6 | define void @caller(i8*, i8*, i32, double) { 7 | call void (i8*, ...)* @callee(i8* %0, i8* %1, i32 %2, double %3) 8 | ret void 9 | } 10 | -------------------------------------------------------------------------------- /test/x86_64/VarArgsPassPtrVAStructLongFloat.ll: -------------------------------------------------------------------------------- 1 | ; ABI: x86_64-none-linux-gnu 2 | ; FUNCTION-TYPE: void (ptr, ...({ long, float })) 3 | 4 | declare void @callee(i8*, ...) 5 | 6 | define void @caller(i8*, i64 %coerce0, float %coerce1) { 7 | %coerce.arg.source = alloca { i64, float }, align 8 8 | %coerce.mem = alloca { i64, float }, align 8 9 | %2 = getelementptr { i64, float }* %coerce.mem, i32 0, i32 0 10 | store i64 %coerce0, i64* %2 11 | %3 = getelementptr { i64, float }* %coerce.mem, i32 0, i32 1 12 | store float %coerce1, float* %3 13 | %4 = load { i64, float }* %coerce.mem 14 | store { i64, float } %4, { i64, float }* %coerce.arg.source 15 | %5 = getelementptr { i64, float }* %coerce.arg.source, i32 0, i32 0 16 | %6 = load i64* %5, align 1 17 | %7 = getelementptr { i64, float }* %coerce.arg.source, i32 0, i32 1 18 | %8 = load float* %7, align 1 19 | call void (i8*, ...)* @callee(i8* %0, i64 %6, float %8) 20 | ret void 21 | } 22 | --------------------------------------------------------------------------------