2c454ef770eb — Leonard Ritter a month ago
* refactored existing platform ABI implementations into separate files
* added stub for aarch64
4 files changed, 331 insertions(+), 262 deletions(-)

A => src/abi_aarch64.cpp
A => src/abi_windows_x64.cpp
A => src/abi_x86_64.cpp
M src/platform_abi.cpp
A => src/abi_aarch64.cpp +50 -0
@@ 0,0 1,50 @@ 
+/*
+    The Scopes Compiler Infrastructure
+    This file is distributed under the MIT License.
+    See LICENSE.md for details.
+*/
+
+#include "platform_abi.hpp"
+#include "types.hpp"
+#include "type.hpp"
+#include "utils.hpp"
+#include "dyn_cast.inc"
+
+#include <assert.h>
+
+#pragma GCC diagnostic ignored "-Wvla-extension"
+
+namespace scopes { namespace abi_aarch64 {
+
+size_t classify(const Type *T, ABIClass *classes) {
+    classes[0] = ABI_CLASS_NO_CLASS;
+    if (is_opaque(T))
+        return 1;
+    T = storage_type(T).assert_ok();
+    size_t sz = size_of(T).assert_ok();
+    if (sz > 8)
+        return 0;
+    switch(T->kind()) {
+    case TK_Array:
+    case TK_Matrix:
+    case TK_Tuple:
+        if (sz <= 1)
+            classes[0] = ABI_CLASS_INTEGERSI8;
+        else if (sz <= 2)
+            classes[0] = ABI_CLASS_INTEGERSI16;
+        else if (sz <= 4)
+            classes[0] = ABI_CLASS_INTEGERSI;
+        else
+            classes[0] = ABI_CLASS_INTEGER;
+        return 1;
+    case TK_Integer:
+    case TK_Pointer:
+    case TK_Real:
+    case TK_Typename:
+    case TK_Vector:
+    default:
+        return 1;
+    }
+}
+
+}} // namespace scopes::abi_aarch64

          
A => src/abi_windows_x64.cpp +50 -0
@@ 0,0 1,50 @@ 
+/*
+    The Scopes Compiler Infrastructure
+    This file is distributed under the MIT License.
+    See LICENSE.md for details.
+*/
+
+#include "platform_abi.hpp"
+#include "types.hpp"
+#include "type.hpp"
+#include "utils.hpp"
+#include "dyn_cast.inc"
+
+#include <assert.h>
+
+#pragma GCC diagnostic ignored "-Wvla-extension"
+
+namespace scopes { namespace abi_windows_x64 {
+
+size_t classify(const Type *T, ABIClass *classes) {
+    classes[0] = ABI_CLASS_NO_CLASS;
+    if (is_opaque(T))
+        return 1;
+    T = storage_type(T).assert_ok();
+    size_t sz = size_of(T).assert_ok();
+    if (sz > 8)
+        return 0;
+    switch(T->kind()) {
+    case TK_Array:
+    case TK_Matrix:
+    case TK_Tuple:
+        if (sz <= 1)
+            classes[0] = ABI_CLASS_INTEGERSI8;
+        else if (sz <= 2)
+            classes[0] = ABI_CLASS_INTEGERSI16;
+        else if (sz <= 4)
+            classes[0] = ABI_CLASS_INTEGERSI;
+        else
+            classes[0] = ABI_CLASS_INTEGER;
+        return 1;
+    case TK_Integer:
+    case TK_Pointer:
+    case TK_Real:
+    case TK_Typename:
+    case TK_Vector:
+    default:
+        return 1;
+    }
+}
+
+}} // namespace scopes::abi_windows_x64

          
A => src/abi_x86_64.cpp +220 -0
@@ 0,0 1,220 @@ 
+/*
+    The Scopes Compiler Infrastructure
+    This file is distributed under the MIT License.
+    See LICENSE.md for details.
+*/
+
+#include "platform_abi.hpp"
+#include "types.hpp"
+#include "type.hpp"
+#include "utils.hpp"
+#include "dyn_cast.inc"
+
+#include <assert.h>
+
+#pragma GCC diagnostic ignored "-Wvla-extension"
+
+namespace scopes { namespace abi_x86_64 {
+
+// x86-64 PS ABI based on https://www.uclibc.org/docs/psABI-x86_64.pdf
+
+static size_t classify(const Type *T, ABIClass *classes, size_t offset);
+
+static size_t classify_tuple_like(size_t size,
+    const Type **fields, size_t count, bool packed,
+    ABIClass *classes, size_t offset) {
+    const size_t UNITS_PER_WORD = 8;
+    size_t words = (size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+    if (size > 32)
+        return 0;
+    for (size_t i = 0; i < MAX_ABI_CLASSES; i++)
+        classes[i] = ABI_CLASS_NO_CLASS;
+    if (!words) {
+        classes[0] = ABI_CLASS_NO_CLASS;
+        return 1;
+    }
+    ABIClass subclasses[MAX_ABI_CLASSES];
+    for (size_t i = 0; i < count; ++i) {
+        auto ET = qualified_storage_type(fields[i]).assert_ok();
+        if (!packed)
+            offset = align(offset, align_of(ET).assert_ok());
+        size_t num = classify (ET, subclasses, offset % 8);
+        if (!num) return 0;
+        for (size_t k = 0; k < num; ++k) {
+            size_t pos = offset / 8;
+            classes[k + pos] =
+                merge_abi_classes (subclasses[k], classes[k + pos]);
+        }
+        offset += size_of(ET).assert_ok();
+    }
+    if (words > 2) {
+        if (classes[0] != ABI_CLASS_SSE)
+            return 0;
+        for (size_t i = 1; i < words; ++i) {
+            if (classes[i] != ABI_CLASS_SSEUP)
+                return 0;
+        }
+    }
+    for (size_t i = 0; i < words; i++) {
+        if (classes[i] == ABI_CLASS_MEMORY)
+            return 0;
+
+        if (classes[i] == ABI_CLASS_SSEUP) {
+            assert(i > 0);
+            if (classes[i - 1] != ABI_CLASS_SSE
+                && classes[i - 1] != ABI_CLASS_SSEUP) {
+                classes[i] = ABI_CLASS_SSE;
+            }
+        }
+
+        if (classes[i] == ABI_CLASS_X87UP) {
+            assert(i > 0);
+            if(classes[i - 1] != ABI_CLASS_X87) {
+                return 0;
+            }
+        }
+    }
+    return words;
+
+}
+
+static size_t classify_array_like(size_t size,
+    const Type *element_type, size_t count,
+    ABIClass *classes, size_t offset) {
+    const size_t UNITS_PER_WORD = 8;
+    size_t words = (size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+    if (size > 32)
+        return 0;
+    for (size_t i = 0; i < MAX_ABI_CLASSES; i++)
+        classes[i] = ABI_CLASS_NO_CLASS;
+    if (!words) {
+        classes[0] = ABI_CLASS_NO_CLASS;
+        return 1;
+    }
+    auto ET = qualified_storage_type(element_type).assert_ok();
+    ABIClass subclasses[MAX_ABI_CLASSES];
+    size_t alignment = align_of(ET).assert_ok();
+    size_t esize = size_of(ET).assert_ok();
+    for (size_t i = 0; i < count; ++i) {
+        offset = align(offset, alignment);
+        size_t num = classify(ET, subclasses, offset % 8);
+        if (!num) return 0;
+        for (size_t k = 0; k < num; ++k) {
+            size_t pos = offset / 8;
+            classes[k + pos] =
+                merge_abi_classes (subclasses[k], classes[k + pos]);
+        }
+        offset += esize;
+    }
+    if (words > 2) {
+        if (classes[0] != ABI_CLASS_SSE)
+            return 0;
+        for (size_t i = 1; i < words; ++i) {
+            if (classes[i] != ABI_CLASS_SSEUP)
+                return 0;
+        }
+    }
+    for (size_t i = 0; i < words; i++) {
+        if (classes[i] == ABI_CLASS_MEMORY)
+            return 0;
+
+        if (classes[i] == ABI_CLASS_SSEUP) {
+            assert(i > 0);
+            if (classes[i - 1] != ABI_CLASS_SSE
+                && classes[i - 1] != ABI_CLASS_SSEUP) {
+                classes[i] = ABI_CLASS_SSE;
+            }
+        }
+
+        if (classes[i] == ABI_CLASS_X87UP) {
+            assert(i > 0);
+            if(classes[i - 1] != ABI_CLASS_X87) {
+                return 0;
+            }
+        }
+    }
+    return words;
+}
+
+static size_t classify(const Type *T, ABIClass *classes, size_t offset) {
+    switch(T->kind()) {
+    case TK_Integer:
+    case TK_Pointer: {
+        size_t size = size_of(T).assert_ok() + offset;
+        if (size <= 4) {
+            classes[0] = ABI_CLASS_INTEGERSI;
+            return 1;
+        } else if (size <= 8) {
+            classes[0] = ABI_CLASS_INTEGER;
+            return 1;
+        } else if (size <= 12) {
+            classes[0] = ABI_CLASS_INTEGER;
+            classes[1] = ABI_CLASS_INTEGERSI;
+            return 2;
+        } else if (size <= 16) {
+            classes[0] = ABI_CLASS_INTEGER;
+            classes[1] = ABI_CLASS_INTEGER;
+            return 2;
+        } else {
+            return 0;
+        }
+    } break;
+    case TK_Real: {
+        size_t size = size_of(T).assert_ok();
+        if (size == 4) {
+            if (!(offset % 8))
+                classes[0] = ABI_CLASS_SSESF;
+            else
+                classes[0] = ABI_CLASS_SSE;
+            return 1;
+        } else if (size == 8) {
+            classes[0] = ABI_CLASS_SSEDF;
+            return 1;
+        } else {
+            assert(false && "illegal type");
+        }
+    } break;
+    case TK_Typename: {
+        if (is_opaque(T)) {
+            classes[0] = ABI_CLASS_NO_CLASS;
+            return 1;
+        } else {
+            return classify(storage_type(T).assert_ok(), classes, offset);
+        }
+    } break;
+    case TK_Vector: {
+        auto tt = cast<VectorType>(T);
+        return classify_array_like(size_of(T).assert_ok(),
+            storage_type(tt->element_type).assert_ok(), tt->count(), classes, offset);
+    } break;
+    case TK_Array:
+    case TK_Matrix: {
+        auto tt = cast<ArrayLikeType>(T);
+        return classify_array_like(size_of(T).assert_ok(),
+            storage_type(tt->element_type).assert_ok(), tt->count(), classes, offset);
+    } break;
+    case TK_Tuple: {
+        auto tt = cast<TupleType>(T);
+        size_t count = tt->values.size();
+        const Type *fields[count];
+        for (size_t i = 0; i < tt->values.size(); ++i) {
+            fields[i] = storage_type(tt->values[i]).assert_ok();
+        }
+        return classify_tuple_like(size_of(T).assert_ok(),
+            fields, count, tt->packed, classes, offset);
+    } break;
+    default: {
+        StyledStream ss;
+        ss << "internal error: type " << T << " unsupported in ABI" << std::endl;
+        assert(false && "not supported in ABI");
+        return 0;
+    } break;
+    }
+    return 0;
+}
+
+size_t classify(const Type *T, ABIClass *classes) {
+    return classify(T, classes, 0);
+}
+
+}} // namespace scopes::abi_x86_64

          
M src/platform_abi.cpp +11 -262
@@ 10,6 10,10 @@ 
 #include "utils.hpp"
 #include "dyn_cast.inc"
 
+#include "abi_x86_64.cpp"
+#include "abi_windows_x64.cpp"
+#include "abi_aarch64.cpp"
+
 #include <assert.h>
 
 #pragma GCC diagnostic ignored "-Wvla-extension"

          
@@ 35,41 39,6 @@ const char *abi_class_to_string(ABIClass
 
 #undef DEF_ABI_CLASS_NAMES
 
-#ifdef SCOPES_WIN32
-
-ABIClass merge_abi_classes(ABIClass class1, ABIClass class2) {
-    if (class1 == class2)
-        return class1;
-
-    if (class1 == ABI_CLASS_NO_CLASS)
-        return class2;
-    if (class2 == ABI_CLASS_NO_CLASS)
-        return class1;
-
-    if (class1 == ABI_CLASS_MEMORY || class2 == ABI_CLASS_MEMORY)
-        return ABI_CLASS_MEMORY;
-
-    if ((class1 == ABI_CLASS_INTEGERSI && class2 == ABI_CLASS_SSESF)
-        || (class2 == ABI_CLASS_INTEGERSI && class1 == ABI_CLASS_SSESF))
-        return ABI_CLASS_INTEGERSI;
-    if (class1 == ABI_CLASS_INTEGER || class1 == ABI_CLASS_INTEGERSI
-        || class2 == ABI_CLASS_INTEGER || class2 == ABI_CLASS_INTEGERSI)
-        return ABI_CLASS_INTEGER;
-
-    if (class1 == ABI_CLASS_X87
-        || class1 == ABI_CLASS_X87UP
-        || class1 == ABI_CLASS_COMPLEX_X87
-        || class2 == ABI_CLASS_X87
-        || class2 == ABI_CLASS_X87UP
-        || class2 == ABI_CLASS_COMPLEX_X87)
-        return ABI_CLASS_MEMORY;
-
-    return ABI_CLASS_SSE;
-}
-
-#else
-// x86-64 PS ABI based on https://www.uclibc.org/docs/psABI-x86_64.pdf
-
 ABIClass merge_abi_classes(ABIClass class1, ABIClass class2) {
     if (class1 == class2)
         return class1;

          
@@ 100,202 69,6 @@ ABIClass merge_abi_classes(ABIClass clas
     return ABI_CLASS_SSE;
 }
 
-static size_t classify(const Type *T, ABIClass *classes, size_t offset);
-
-static size_t classify_tuple_like(size_t size,
-    const Type **fields, size_t count, bool packed,
-    ABIClass *classes, size_t offset) {
-    const size_t UNITS_PER_WORD = 8;
-    size_t words = (size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
-    if (size > 32)
-        return 0;
-    for (size_t i = 0; i < MAX_ABI_CLASSES; i++)
-        classes[i] = ABI_CLASS_NO_CLASS;
-    if (!words) {
-        classes[0] = ABI_CLASS_NO_CLASS;
-        return 1;
-    }
-    ABIClass subclasses[MAX_ABI_CLASSES];
-    for (size_t i = 0; i < count; ++i) {
-        auto ET = qualified_storage_type(fields[i]).assert_ok();
-        if (!packed)
-            offset = align(offset, align_of(ET).assert_ok());
-        size_t num = classify (ET, subclasses, offset % 8);
-        if (!num) return 0;
-        for (size_t k = 0; k < num; ++k) {
-            size_t pos = offset / 8;
-            classes[k + pos] =
-                merge_abi_classes (subclasses[k], classes[k + pos]);
-        }
-        offset += size_of(ET).assert_ok();
-    }
-    if (words > 2) {
-        if (classes[0] != ABI_CLASS_SSE)
-            return 0;
-        for (size_t i = 1; i < words; ++i) {
-            if (classes[i] != ABI_CLASS_SSEUP)
-                return 0;
-        }
-    }
-    for (size_t i = 0; i < words; i++) {
-        if (classes[i] == ABI_CLASS_MEMORY)
-            return 0;
-
-        if (classes[i] == ABI_CLASS_SSEUP) {
-            assert(i > 0);
-            if (classes[i - 1] != ABI_CLASS_SSE
-                && classes[i - 1] != ABI_CLASS_SSEUP) {
-                classes[i] = ABI_CLASS_SSE;
-            }
-        }
-
-        if (classes[i] == ABI_CLASS_X87UP) {
-            assert(i > 0);
-            if(classes[i - 1] != ABI_CLASS_X87) {
-                return 0;
-            }
-        }
-    }
-    return words;
-
-}
-
-static size_t classify_array_like(size_t size,
-    const Type *element_type, size_t count,
-    ABIClass *classes, size_t offset) {
-    const size_t UNITS_PER_WORD = 8;
-    size_t words = (size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
-    if (size > 32)
-        return 0;
-    for (size_t i = 0; i < MAX_ABI_CLASSES; i++)
-        classes[i] = ABI_CLASS_NO_CLASS;
-    if (!words) {
-        classes[0] = ABI_CLASS_NO_CLASS;
-        return 1;
-    }
-    auto ET = qualified_storage_type(element_type).assert_ok();
-    ABIClass subclasses[MAX_ABI_CLASSES];
-    size_t alignment = align_of(ET).assert_ok();
-    size_t esize = size_of(ET).assert_ok();
-    for (size_t i = 0; i < count; ++i) {
-        offset = align(offset, alignment);
-        size_t num = classify(ET, subclasses, offset % 8);
-        if (!num) return 0;
-        for (size_t k = 0; k < num; ++k) {
-            size_t pos = offset / 8;
-            classes[k + pos] =
-                merge_abi_classes (subclasses[k], classes[k + pos]);
-        }
-        offset += esize;
-    }
-    if (words > 2) {
-        if (classes[0] != ABI_CLASS_SSE)
-            return 0;
-        for (size_t i = 1; i < words; ++i) {
-            if (classes[i] != ABI_CLASS_SSEUP)
-                return 0;
-        }
-    }
-    for (size_t i = 0; i < words; i++) {
-        if (classes[i] == ABI_CLASS_MEMORY)
-            return 0;
-
-        if (classes[i] == ABI_CLASS_SSEUP) {
-            assert(i > 0);
-            if (classes[i - 1] != ABI_CLASS_SSE
-                && classes[i - 1] != ABI_CLASS_SSEUP) {
-                classes[i] = ABI_CLASS_SSE;
-            }
-        }
-
-        if (classes[i] == ABI_CLASS_X87UP) {
-            assert(i > 0);
-            if(classes[i - 1] != ABI_CLASS_X87) {
-                return 0;
-            }
-        }
-    }
-    return words;
-}
-
-static size_t classify(const Type *T, ABIClass *classes, size_t offset) {
-    switch(T->kind()) {
-    case TK_Integer:
-    case TK_Pointer: {
-        size_t size = size_of(T).assert_ok() + offset;
-        if (size <= 4) {
-            classes[0] = ABI_CLASS_INTEGERSI;
-            return 1;
-        } else if (size <= 8) {
-            classes[0] = ABI_CLASS_INTEGER;
-            return 1;
-        } else if (size <= 12) {
-            classes[0] = ABI_CLASS_INTEGER;
-            classes[1] = ABI_CLASS_INTEGERSI;
-            return 2;
-        } else if (size <= 16) {
-            classes[0] = ABI_CLASS_INTEGER;
-            classes[1] = ABI_CLASS_INTEGER;
-            return 2;
-        } else {
-            return 0;
-        }
-    } break;
-    case TK_Real: {
-        size_t size = size_of(T).assert_ok();
-        if (size == 4) {
-            if (!(offset % 8))
-                classes[0] = ABI_CLASS_SSESF;
-            else
-                classes[0] = ABI_CLASS_SSE;
-            return 1;
-        } else if (size == 8) {
-            classes[0] = ABI_CLASS_SSEDF;
-            return 1;
-        } else {
-            assert(false && "illegal type");
-        }
-    } break;
-    case TK_Typename: {
-        if (is_opaque(T)) {
-            classes[0] = ABI_CLASS_NO_CLASS;
-            return 1;
-        } else {
-            return classify(storage_type(T).assert_ok(), classes, offset);
-        }
-    } break;
-    case TK_Vector: {
-        auto tt = cast<VectorType>(T);
-        return classify_array_like(size_of(T).assert_ok(),
-            storage_type(tt->element_type).assert_ok(), tt->count(), classes, offset);
-    } break;
-    case TK_Array:
-    case TK_Matrix: {
-        auto tt = cast<ArrayLikeType>(T);
-        return classify_array_like(size_of(T).assert_ok(),
-            storage_type(tt->element_type).assert_ok(), tt->count(), classes, offset);
-    } break;
-    case TK_Tuple: {
-        auto tt = cast<TupleType>(T);
-        size_t count = tt->values.size();
-        const Type *fields[count];
-        for (size_t i = 0; i < tt->values.size(); ++i) {
-            fields[i] = storage_type(tt->values[i]).assert_ok();
-        }
-        return classify_tuple_like(size_of(T).assert_ok(),
-            fields, count, tt->packed, classes, offset);
-    } break;
-    default: {
-        StyledStream ss;
-        ss << "internal error: type " << T << " unsupported in ABI" << std::endl;
-        assert(false && "not supported in ABI");
-        return 0;
-    } break;
-    }
-    return 0;
-}
-#endif // SCOPES_WIN32
-
 size_t abi_classify(const Type *T, ABIClass *classes) {
     //const Type *ST = strip_qualifiers(T);
     if (T->kind() == TK_Arguments) {

          
@@ 306,37 79,14 @@ size_t abi_classify(const Type *T, ABICl
         T = cast<ArgumentsType>(T)->to_tuple_type();
     }
     T = qualified_storage_type(T).assert_ok();
-#ifdef SCOPES_WIN32
-    classes[0] = ABI_CLASS_NO_CLASS;
-    if (is_opaque(T))
-        return 1;
-    T = storage_type(T).assert_ok();
-    size_t sz = size_of(T).assert_ok();
-    if (sz > 8)
-        return 0;
-    switch(T->kind()) {
-    case TK_Array:
-    case TK_Matrix:
-    case TK_Tuple:
-        if (sz <= 1)
-            classes[0] = ABI_CLASS_INTEGERSI8;
-        else if (sz <= 2)
-            classes[0] = ABI_CLASS_INTEGERSI16;
-        else if (sz <= 4)
-            classes[0] = ABI_CLASS_INTEGERSI;
-        else
-            classes[0] = ABI_CLASS_INTEGER;
-        return 1;
-    case TK_Integer:
-    case TK_Pointer:
-    case TK_Real:
-    case TK_Typename:
-    case TK_Vector:
-    default:
-        return 1;
-    }
+    size_t sz;
+#if defined(SCOPES_WIN32)
+    sz = abi_windows_x64::classify(T, classes);
+#elif defined(__amd64__)
+    sz = abi_x86_64::classify(T, classes);
 #else
-    size_t sz = classify(T, classes, 0);
+#error unsupported platform ABI
+#endif
 #if 0
     if (sz) {
         StyledStream ss(std::cout);

          
@@ 348,7 98,6 @@ size_t abi_classify(const Type *T, ABICl
     }
 #endif
     return sz;
-#endif
 }
 
 bool is_memory_class(const Type *T) {