authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-09-07 18:34:19-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-09-07 18:51:34-04:00
log85534a26c6ddea6277e79b12b759188689f3da43
tree5454004b73e9e940174474666eea9b20dcefe557
parentb18af37c578b118a245c911508d73ed23c303ee0
signaturelock-open Commit is signed but in an unrecognized format.

stage1: function to classify x86_64 abi types


1 files changed, 150 insertions(+), 91 deletions(-)

src/codegen.cpp+150-91
...@@ -1894,6 +1894,91 @@ static void give_up_with_c_abi_error(CodeGen *g, AstNode *source_node) {...@@ -1894,6 +1894,91 @@ static void give_up_with_c_abi_error(CodeGen *g, AstNode *source_node) {
1894 report_errors_and_exit(g);1894 report_errors_and_exit(g);
1895}1895}
18961896
1897static LLVMValueRef build_alloca(CodeGen *g, ZigType *type_entry, const char *name, uint32_t alignment) {
1898 assert(alignment > 0);
1899 LLVMValueRef result = LLVMBuildAlloca(g->builder, type_entry->type_ref, name);
1900 LLVMSetAlignment(result, alignment);
1901 return result;
1902}
1903
1904enum X64CABIClass {
1905 X64CABIClass_Unknown,
1906 X64CABIClass_MEMORY,
1907 X64CABIClass_INTEGER,
1908 X64CABIClass_SSE,
1909};
1910
1911static X64CABIClass type_c_abi_x86_64_class(CodeGen *g, ZigType *ty) {
1912 size_t ty_size = type_size(g, ty);
1913 if (get_codegen_ptr_type(ty) != nullptr)
1914 return X64CABIClass_INTEGER;
1915 switch (ty->id) {
1916 case ZigTypeIdEnum:
1917 case ZigTypeIdInt:
1918 case ZigTypeIdBool:
1919 return X64CABIClass_INTEGER;
1920 case ZigTypeIdFloat:
1921 return X64CABIClass_SSE;
1922 case ZigTypeIdStruct: {
1923 // "If the size of an object is larger than four eightbytes, or it contains unaligned
1924 // fields, it has class MEMORY"
1925 if (ty_size > 32)
1926 return X64CABIClass_MEMORY;
1927 if (ty->data.structure.layout != ContainerLayoutExtern) {
1928 // TODO determine whether packed structs have any unaligned fields
1929 return X64CABIClass_Unknown;
1930 }
1931 // "If the size of the aggregate exceeds two eightbytes and the first eight-
1932 // byte isn’t SSE or any other eightbyte isn’t SSEUP, the whole argument
1933 // is passed in memory."
1934 if (ty_size > 16) {
1935 // Zig doesn't support vectors and large fp registers yet, so this will always
1936 // be memory.
1937 return X64CABIClass_MEMORY;
1938 }
1939 X64CABIClass working_class = X64CABIClass_Unknown;
1940 for (uint32_t i = 0; i < ty->data.structure.src_field_count; i += 1) {
1941 X64CABIClass field_class = type_c_abi_x86_64_class(g, ty->data.structure.fields->type_entry);
1942 if (field_class == X64CABIClass_Unknown)
1943 return X64CABIClass_Unknown;
1944 if (i == 0 || field_class == X64CABIClass_MEMORY || working_class == X64CABIClass_SSE) {
1945 working_class = field_class;
1946 }
1947 }
1948 return working_class;
1949 }
1950 case ZigTypeIdUnion: {
1951 // "If the size of an object is larger than four eightbytes, or it contains unaligned
1952 // fields, it has class MEMORY"
1953 if (ty_size > 32)
1954 return X64CABIClass_MEMORY;
1955 if (ty->data.unionation.layout != ContainerLayoutExtern)
1956 return X64CABIClass_MEMORY;
1957 // "If the size of the aggregate exceeds two eightbytes and the first eight-
1958 // byte isn’t SSE or any other eightbyte isn’t SSEUP, the whole argument
1959 // is passed in memory."
1960 if (ty_size > 16) {
1961 // Zig doesn't support vectors and large fp registers yet, so this will always
1962 // be memory.
1963 return X64CABIClass_MEMORY;
1964 }
1965 X64CABIClass working_class = X64CABIClass_Unknown;
1966 for (uint32_t i = 0; i < ty->data.unionation.src_field_count; i += 1) {
1967 X64CABIClass field_class = type_c_abi_x86_64_class(g, ty->data.unionation.fields->type_entry);
1968 if (field_class == X64CABIClass_Unknown)
1969 return X64CABIClass_Unknown;
1970 if (i == 0 || field_class == X64CABIClass_MEMORY || working_class == X64CABIClass_SSE) {
1971 working_class = field_class;
1972 }
1973 }
1974 return working_class;
1975 }
1976 default:
1977 return X64CABIClass_Unknown;
1978 }
1979}
1980
1981// NOTE this does not depend on x86_64
1897static bool type_is_c_abi_int(CodeGen *g, ZigType *ty) {1982static bool type_is_c_abi_int(CodeGen *g, ZigType *ty) {
1898 size_t ty_size = type_size(g, ty);1983 size_t ty_size = type_size(g, ty);
1899 if (ty_size > g->pointer_size_bytes)1984 if (ty_size > g->pointer_size_bytes)
...@@ -1905,13 +1990,6 @@ static bool type_is_c_abi_int(CodeGen *g, ZigType *ty) {...@@ -1905,13 +1990,6 @@ static bool type_is_c_abi_int(CodeGen *g, ZigType *ty) {
1905 get_codegen_ptr_type(ty) != nullptr);1990 get_codegen_ptr_type(ty) != nullptr);
1906}1991}
19071992
1908static LLVMValueRef build_alloca(CodeGen *g, ZigType *type_entry, const char *name, uint32_t alignment) {
1909 assert(alignment > 0);
1910 LLVMValueRef result = LLVMBuildAlloca(g->builder, type_entry->type_ref, name);
1911 LLVMSetAlignment(result, alignment);
1912 return result;
1913}
1914
1915static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk, size_t src_i) {1993static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk, size_t src_i) {
1916 // Initialized from the type for some walks, but because of C var args,1994 // Initialized from the type for some walks, but because of C var args,
1917 // initialized based on callsite instructions for that one.1995 // initialized based on callsite instructions for that one.
...@@ -2047,98 +2125,79 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_...@@ -2047,98 +2125,79 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_
2047 }2125 }
20482126
2049 if (g->zig_target.arch.arch == ZigLLVM_x86_64) {2127 if (g->zig_target.arch.arch == ZigLLVM_x86_64) {
2128 X64CABIClass abi_class = type_c_abi_x86_64_class(g, ty);
2050 size_t ty_size = type_size(g, ty);2129 size_t ty_size = type_size(g, ty);
2051 if (ty->id == ZigTypeIdStruct || ty->id == ZigTypeIdUnion) {2130 if (abi_class == X64CABIClass_MEMORY) {
2052 assert(handle_is_ptr(ty));2131 assert(handle_is_ptr(ty));
20532132 switch (fn_walk->id) {
2054 // "If the size of an object is larger than four eightbytes, or it contains unaligned2133 case FnWalkIdAttrs:
2055 // fields, it has class MEMORY"2134 addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "byval");
2056 if (ty_size > 32) {2135 addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "nonnull");
2057 switch (fn_walk->id) {2136 fn_walk->data.attrs.gen_i += 1;
2058 case FnWalkIdAttrs:2137 break;
2059 addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "byval");2138 case FnWalkIdCall:
2060 addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "nonnull");2139 fn_walk->data.call.gen_param_values->append(val);
2061 fn_walk->data.attrs.gen_i += 1;2140 break;
2062 break;2141 case FnWalkIdTypes: {
2063 case FnWalkIdCall:2142 ZigType *gen_type = get_pointer_to_type(g, ty, true);
2064 fn_walk->data.call.gen_param_values->append(val);2143 fn_walk->data.types.gen_param_types->append(gen_type->type_ref);
2065 break;2144 fn_walk->data.types.param_di_types->append(gen_type->di_type);
2066 case FnWalkIdTypes: {2145 break;
2067 ZigType *gen_type = get_pointer_to_type(g, ty, true);
2068 fn_walk->data.types.gen_param_types->append(gen_type->type_ref);
2069 fn_walk->data.types.param_di_types->append(gen_type->di_type);
2070 break;
2071 }
2072 case FnWalkIdVars: {
2073 di_arg_index = fn_walk->data.vars.gen_i;
2074 var->value_ref = LLVMGetParam(llvm_fn, fn_walk->data.vars.gen_i);
2075 dest_ty = get_pointer_to_type(g, ty, false);
2076 fn_walk->data.vars.gen_i += 1;
2077 goto var_ok;
2078 }
2079 case FnWalkIdInits:
2080 if (var->decl_node) {
2081 gen_var_debug_decl(g, var);
2082 }
2083 fn_walk->data.inits.gen_i += 1;
2084 break;
2085 }2146 }
2086 return true;2147 case FnWalkIdVars: {
2087 }2148 di_arg_index = fn_walk->data.vars.gen_i;
2088 }2149 var->value_ref = LLVMGetParam(llvm_fn, fn_walk->data.vars.gen_i);
2089 if (ty->id == ZigTypeIdStruct) {2150 dest_ty = get_pointer_to_type(g, ty, false);
2090 assert(handle_is_ptr(ty));2151 fn_walk->data.vars.gen_i += 1;
2091 // "If the size of the aggregate exceeds a single eightbyte, each is classified2152 goto var_ok;
2092 // separately. Each eightbyte gets initialized to class NO_CLASS."2153 }
2093 if (ty_size <= 8) {2154 case FnWalkIdInits:
2094 bool contains_int = false;2155 if (var->decl_node) {
2095 for (size_t i = 0; i < ty->data.structure.src_field_count; i += 1) {2156 gen_var_debug_decl(g, var);
2096 if (type_is_c_abi_int(g, ty->data.structure.fields[i].type_entry)) {
2097 contains_int = true;
2098 break;
2099 }2157 }
2158 fn_walk->data.inits.gen_i += 1;
2159 break;
2160 }
2161 return true;
2162 } else if (abi_class == X64CABIClass_INTEGER && ty_size <= 8) {
2163 switch (fn_walk->id) {
2164 case FnWalkIdAttrs:
2165 fn_walk->data.attrs.gen_i += 1;
2166 break;
2167 case FnWalkIdCall: {
2168 LLVMTypeRef ptr_to_int_type_ref = LLVMPointerType(LLVMIntType((unsigned)ty_size * 8), 0);
2169 LLVMValueRef bitcasted = LLVMBuildBitCast(g->builder, val, ptr_to_int_type_ref, "");
2170 LLVMValueRef loaded = LLVMBuildLoad(g->builder, bitcasted, "");
2171 fn_walk->data.call.gen_param_values->append(loaded);
2172 break;
2100 }2173 }
2101 if (contains_int) {2174 case FnWalkIdTypes: {
2102 switch (fn_walk->id) {2175 ZigType *gen_type = get_int_type(g, false, ty_size * 8);
2103 case FnWalkIdAttrs:2176 fn_walk->data.types.gen_param_types->append(gen_type->type_ref);
2104 fn_walk->data.attrs.gen_i += 1;2177 fn_walk->data.types.param_di_types->append(gen_type->di_type);
2105 break;2178 break;
2106 case FnWalkIdCall: {2179 }
2107 LLVMTypeRef ptr_to_int_type_ref = LLVMPointerType(LLVMIntType((unsigned)ty_size * 8), 0);2180 case FnWalkIdVars: {
2108 LLVMValueRef bitcasted = LLVMBuildBitCast(g->builder, val, ptr_to_int_type_ref, "");2181 di_arg_index = fn_walk->data.vars.gen_i;
2109 LLVMValueRef loaded = LLVMBuildLoad(g->builder, bitcasted, "");2182 var->value_ref = build_alloca(g, ty, buf_ptr(&var->name), var->align_bytes);
2110 fn_walk->data.call.gen_param_values->append(loaded);2183 fn_walk->data.vars.gen_i += 1;
2111 break;2184 dest_ty = ty;
2112 }2185 goto var_ok;
2113 case FnWalkIdTypes: {2186 }
2114 ZigType *gen_type = get_int_type(g, false, ty_size * 8);2187 case FnWalkIdInits: {
2115 fn_walk->data.types.gen_param_types->append(gen_type->type_ref);2188 clear_debug_source_node(g);
2116 fn_walk->data.types.param_di_types->append(gen_type->di_type);2189 LLVMValueRef arg = LLVMGetParam(llvm_fn, fn_walk->data.inits.gen_i);
2117 break;2190 LLVMTypeRef ptr_to_int_type_ref = LLVMPointerType(LLVMIntType((unsigned)ty_size * 8), 0);
2118 }2191 LLVMValueRef bitcasted = LLVMBuildBitCast(g->builder, var->value_ref, ptr_to_int_type_ref, "");
2119 case FnWalkIdVars: {2192 gen_store_untyped(g, arg, bitcasted, var->align_bytes, false);
2120 di_arg_index = fn_walk->data.vars.gen_i;2193 if (var->decl_node) {
2121 var->value_ref = build_alloca(g, ty, buf_ptr(&var->name), var->align_bytes);2194 gen_var_debug_decl(g, var);
2122 fn_walk->data.vars.gen_i += 1;
2123 dest_ty = ty;
2124 goto var_ok;
2125 }
2126 case FnWalkIdInits: {
2127 clear_debug_source_node(g);
2128 LLVMValueRef arg = LLVMGetParam(llvm_fn, fn_walk->data.inits.gen_i);
2129 LLVMTypeRef ptr_to_int_type_ref = LLVMPointerType(LLVMIntType((unsigned)ty_size * 8), 0);
2130 LLVMValueRef bitcasted = LLVMBuildBitCast(g->builder, var->value_ref, ptr_to_int_type_ref, "");
2131 gen_store_untyped(g, arg, bitcasted, var->align_bytes, false);
2132 if (var->decl_node) {
2133 gen_var_debug_decl(g, var);
2134 }
2135 fn_walk->data.inits.gen_i += 1;
2136 break;
2137 }
2138 }2195 }
2139 return true;2196 fn_walk->data.inits.gen_i += 1;
2197 break;
2140 }2198 }
2141 }2199 }
2200 return true;
2142 }2201 }
2143 }2202 }
2144 if (source_node != nullptr) {2203 if (source_node != nullptr) {