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) {
18941894 report_errors_and_exit(g);
18951895}
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
18971982static bool type_is_c_abi_int(CodeGen *g, ZigType *ty) {
18981983 size_t ty_size = type_size(g, ty);
18991984 if (ty_size > g->pointer_size_bytes)
......@@ -1905,13 +1990,6 @@ static bool type_is_c_abi_int(CodeGen *g, ZigType *ty) {
19051990 get_codegen_ptr_type(ty) != nullptr);
19061991}
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
19151993static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk, size_t src_i) {
19161994 // Initialized from the type for some walks, but because of C var args,
19171995 // 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_
20472125 }
20482126
20492127 if (g->zig_target.arch.arch == ZigLLVM_x86_64) {
2128 X64CABIClass abi_class = type_c_abi_x86_64_class(g, ty);
20502129 size_t ty_size = type_size(g, ty);
2051 if (ty->id == ZigTypeIdStruct || ty->id == ZigTypeIdUnion) {
2130 if (abi_class == X64CABIClass_MEMORY) {
20522131 assert(handle_is_ptr(ty));
2053
2054 // "If the size of an object is larger than four eightbytes, or it contains unaligned
2055 // fields, it has class MEMORY"
2056 if (ty_size > 32) {
2057 switch (fn_walk->id) {
2058 case FnWalkIdAttrs:
2059 addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "byval");
2060 addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "nonnull");
2061 fn_walk->data.attrs.gen_i += 1;
2062 break;
2063 case FnWalkIdCall:
2064 fn_walk->data.call.gen_param_values->append(val);
2065 break;
2066 case FnWalkIdTypes: {
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;
2132 switch (fn_walk->id) {
2133 case FnWalkIdAttrs:
2134 addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "byval");
2135 addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "nonnull");
2136 fn_walk->data.attrs.gen_i += 1;
2137 break;
2138 case FnWalkIdCall:
2139 fn_walk->data.call.gen_param_values->append(val);
2140 break;
2141 case FnWalkIdTypes: {
2142 ZigType *gen_type = get_pointer_to_type(g, ty, true);
2143 fn_walk->data.types.gen_param_types->append(gen_type->type_ref);
2144 fn_walk->data.types.param_di_types->append(gen_type->di_type);
2145 break;
20852146 }
2086 return true;
2087 }
2088 }
2089 if (ty->id == ZigTypeIdStruct) {
2090 assert(handle_is_ptr(ty));
2091 // "If the size of the aggregate exceeds a single eightbyte, each is classified
2092 // separately. Each eightbyte gets initialized to class NO_CLASS."
2093 if (ty_size <= 8) {
2094 bool contains_int = false;
2095 for (size_t i = 0; i < ty->data.structure.src_field_count; i += 1) {
2096 if (type_is_c_abi_int(g, ty->data.structure.fields[i].type_entry)) {
2097 contains_int = true;
2098 break;
2147 case FnWalkIdVars: {
2148 di_arg_index = fn_walk->data.vars.gen_i;
2149 var->value_ref = LLVMGetParam(llvm_fn, fn_walk->data.vars.gen_i);
2150 dest_ty = get_pointer_to_type(g, ty, false);
2151 fn_walk->data.vars.gen_i += 1;
2152 goto var_ok;
2153 }
2154 case FnWalkIdInits:
2155 if (var->decl_node) {
2156 gen_var_debug_decl(g, var);
20992157 }
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;
21002173 }
2101 if (contains_int) {
2102 switch (fn_walk->id) {
2103 case FnWalkIdAttrs:
2104 fn_walk->data.attrs.gen_i += 1;
2105 break;
2106 case FnWalkIdCall: {
2107 LLVMTypeRef ptr_to_int_type_ref = LLVMPointerType(LLVMIntType((unsigned)ty_size * 8), 0);
2108 LLVMValueRef bitcasted = LLVMBuildBitCast(g->builder, val, ptr_to_int_type_ref, "");
2109 LLVMValueRef loaded = LLVMBuildLoad(g->builder, bitcasted, "");
2110 fn_walk->data.call.gen_param_values->append(loaded);
2111 break;
2112 }
2113 case FnWalkIdTypes: {
2114 ZigType *gen_type = get_int_type(g, false, ty_size * 8);
2115 fn_walk->data.types.gen_param_types->append(gen_type->type_ref);
2116 fn_walk->data.types.param_di_types->append(gen_type->di_type);
2117 break;
2118 }
2119 case FnWalkIdVars: {
2120 di_arg_index = fn_walk->data.vars.gen_i;
2121 var->value_ref = build_alloca(g, ty, buf_ptr(&var->name), var->align_bytes);
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 }
2174 case FnWalkIdTypes: {
2175 ZigType *gen_type = get_int_type(g, false, ty_size * 8);
2176 fn_walk->data.types.gen_param_types->append(gen_type->type_ref);
2177 fn_walk->data.types.param_di_types->append(gen_type->di_type);
2178 break;
2179 }
2180 case FnWalkIdVars: {
2181 di_arg_index = fn_walk->data.vars.gen_i;
2182 var->value_ref = build_alloca(g, ty, buf_ptr(&var->name), var->align_bytes);
2183 fn_walk->data.vars.gen_i += 1;
2184 dest_ty = ty;
2185 goto var_ok;
2186 }
2187 case FnWalkIdInits: {
2188 clear_debug_source_node(g);
2189 LLVMValueRef arg = LLVMGetParam(llvm_fn, fn_walk->data.inits.gen_i);
2190 LLVMTypeRef ptr_to_int_type_ref = LLVMPointerType(LLVMIntType((unsigned)ty_size * 8), 0);
2191 LLVMValueRef bitcasted = LLVMBuildBitCast(g->builder, var->value_ref, ptr_to_int_type_ref, "");
2192 gen_store_untyped(g, arg, bitcasted, var->align_bytes, false);
2193 if (var->decl_node) {
2194 gen_var_debug_decl(g, var);
21382195 }
2139 return true;
2196 fn_walk->data.inits.gen_i += 1;
2197 break;
21402198 }
21412199 }
2200 return true;
21422201 }
21432202 }
21442203 if (source_node != nullptr) {