support inline arrays on stack (#726)

This commit is contained in:
water111
2021-07-26 21:39:05 -04:00
committed by GitHub
parent 1352adb6d4
commit eee8390ec0
22 changed files with 124 additions and 66 deletions
+2 -1
View File
@@ -261,7 +261,8 @@ TP_Type get_stack_type_at_constant_offset(int offset,
if (offset == structure.hint.stack_offset) {
// special case just getting the variable
if (structure.hint.container_type == StackStructureHint::ContainerType::NONE) {
if (structure.hint.container_type == StackStructureHint::ContainerType::NONE ||
structure.hint.container_type == StackStructureHint::ContainerType::INLINE_ARRAY) {
return TP_Type::make_from_ts(coerce_to_reg_type(structure.ref_type));
}
}
+26 -5
View File
@@ -518,12 +518,12 @@ void Env::set_stack_structure_hints(const std::vector<StackStructureHint>& hints
for (auto& hint : hints) {
StackStructureEntry entry;
entry.hint = hint;
// parse the type spec.
TypeSpec base_typespec = dts->parse_type_spec(hint.element_type);
auto type_info = dts->ts.lookup_type(base_typespec);
switch (hint.container_type) {
case StackStructureHint::ContainerType::NONE:
case StackStructureHint::ContainerType::NONE: {
// parse the type spec.
TypeSpec base_typespec = dts->parse_type_spec(hint.element_type);
auto type_info = dts->ts.lookup_type(base_typespec);
// just a plain object on the stack.
if (!type_info->is_reference()) {
throw std::runtime_error(
@@ -540,8 +540,29 @@ void Env::set_stack_structure_hints(const std::vector<StackStructureHint>& hints
entry.ref_type.print(), entry.hint.stack_offset,
type_info->get_in_memory_alignment());
}
} break;
break;
case StackStructureHint::ContainerType::INLINE_ARRAY: {
TypeSpec base_typespec = dts->parse_type_spec(hint.element_type);
auto type_info = dts->ts.lookup_type(base_typespec);
if (!type_info->is_reference()) {
throw std::runtime_error(
fmt::format("Stack inline-array element type {} is not a reference and cannot be "
"stored in an inline-array. Use an array instead.",
base_typespec.print()));
}
entry.ref_type = TypeSpec("inline-array", {TypeSpec(base_typespec)});
entry.size = 1; // we assume that there is no constant propagation into this array and
// make this only trigger in get_stack_type if we hit exactly.
// sanity check the alignment
if (align(entry.hint.stack_offset, type_info->get_in_memory_alignment()) !=
entry.hint.stack_offset) {
lg::error("Misaligned stack variable of type {} offset {} required align {}\n",
entry.ref_type.print(), entry.hint.stack_offset,
type_info->get_in_memory_alignment());
}
} break;
default:
assert(false);
}
+4
View File
@@ -2617,6 +2617,10 @@ goos::Object StackStructureDefElement::to_form_internal(const Env&) const {
case StackStructureHint::ContainerType::NONE:
return pretty_print::build_list(
fmt::format("new 'stack-no-clear '{}", m_entry.ref_type.print()));
case StackStructureHint::ContainerType::INLINE_ARRAY:
return pretty_print::build_list(fmt::format("new 'stack-no-clear 'inline-array '{} {}",
m_entry.ref_type.get_single_arg().print(),
m_entry.hint.container_size));
default:
assert(false);
}
+4 -1
View File
@@ -181,4 +181,7 @@
- `meters`, `degrees`, and `seconds` types have been added.
- Bitfields with `symbol` fields used in an immediate `(new 'static ...)` can now define the symbol in the `new` form.
- Bitfields with `float` fields used in an immediate `(new 'static ...)` in code can use a non-constant floating point value.
- Multiple variables assigned to the same register using `:reg` in `rlet` (or overlapping with `self` in a behavior) will now be merged to a single variable instead of causing a compiler error. Variables will have their own type, but they will all be an alias of the same exact register.
- Multiple variables assigned to the same register using `:reg` in `rlet` (or overlapping with `self` in a behavior) will now be merged to a single variable instead of causing a compiler error. Variables will have their own type, but they will all be an alias of the same exact register.
- Stack arrays of uint128 will now be 16-byte aligned instead of sometimes only 8.
- Inline arrays of structures are now allowed with `stack-no-clear`.
- Creating arrays on the stack now must be done with `stack-no-clear` as they are not memset to 0 or constructed in any way.
+1 -1
View File
@@ -266,7 +266,7 @@
(defmacro print128 (value &key (stream #t))
"Print a 128-bit value"
`(let ((temp (new 'stack 'array 'uint64 2)))
`(let ((temp (new 'stack-no-clear 'array 'uint64 2)))
(set! (-> (the (pointer uint128) temp)) ,value)
(format ,stream "#x~16X~16X" (-> temp 1) (-> temp 0))
)
+1 -1
View File
@@ -2265,7 +2265,7 @@
This will then return the value of the function you called!"
(rlet ((pp :reg r13 :type process))
(let ((param-array (new 'stack 'array 'uint64 6))
(let ((param-array (new 'stack-no-clear 'array 'uint64 6))
)
;; copy params to the stack.
+15 -5
View File
@@ -3,6 +3,7 @@
#include "common/type_system/defenum.h"
#include "common/type_system/deftype.h"
#include "goalc/emitter/CallingConvention.h"
#include "common/util/math_util.h"
namespace {
@@ -1022,6 +1023,9 @@ Val* Compiler::compile_stack_new(const goos::Object& form,
auto type_of_object = parse_typespec(unquote(type));
auto fe = get_parent_env_of_type<FunctionEnv>(env);
if (type_of_object == TypeSpec("inline-array") || type_of_object == TypeSpec("array")) {
if (call_constructor) {
throw_compiler_error(form, "Constructing stack arrays is not yet supported");
}
bool is_inline = type_of_object == TypeSpec("inline-array");
auto elt_type = quoted_sym_as_string(pair_car(*rest));
rest = &pair_cdr(*rest);
@@ -1050,16 +1054,22 @@ Val* Compiler::compile_stack_new(const goos::Object& form,
if (!info.can_deref) {
throw_compiler_error(form, "Cannot make an {} of {}\n", type_of_object.print(), ts.print());
}
auto type_info = m_ts.lookup_type(ts.get_single_arg());
if (!m_ts.lookup_type(elt_type)->is_reference()) {
// not a reference type
int size_in_bytes = info.stride * constant_count;
auto addr = fe->allocate_stack_variable(ts, size_in_bytes);
auto addr = fe->allocate_aligned_stack_variable(ts, size_in_bytes,
type_info->get_in_memory_alignment());
return addr;
}
// todo
throw_compiler_error(form, "Static array of type {} is not yet supported.", ts.print());
return get_none();
int stride =
align(type_info->get_size_in_memory(), type_info->get_inline_array_stride_alignment());
assert(stride == info.stride);
int size_in_bytes = info.stride * constant_count;
auto addr = fe->allocate_aligned_stack_variable(ts, size_in_bytes, stride);
return addr;
} else {
auto ti = m_ts.lookup_type(type_of_object);
@@ -3,7 +3,7 @@
(format #t "TARGET FUNCTION ~D ~D ~D~%" a0 a1 a2)
(format #t "~D ~D ~D~%" a3 a4 a5)
(let ((stack-arr (new 'stack 'array 'uint8 12)))
(let ((stack-arr (new 'stack-no-clear 'array 'uint8 12)))
(format #t "Stack Alignemnt ~D/16~%" (logand 15 (the uint stack-arr)))
)
@@ -28,7 +28,7 @@
)
(defun target-function-2 ()
(let ((stack-var (new 'stack 'array 'int32 1)))
(let ((stack-var (new 'stack-no-clear 'array 'int32 1)))
(set! (-> stack-var) 0)
(countdown (i 10)
(format #t "proc2: ~D~%" (-> stack-var))
@@ -61,7 +61,7 @@
(defun init-child-proc (a0 a1 a2 a3 a4 a5)
(format #t "Args: ~D ~D ~D~%" a0 a1 a2)
(format #t "~D ~D ~D~%" a3 a4 a5)
(let ((stack-arr (new 'stack 'array 'uint8 12)))
(let ((stack-arr (new 'stack-no-clear 'array 'uint8 12)))
(format #t "Stack Alignemnt ~D/16~%" (logand 15 (the uint stack-arr)))
)
(if (eq? a0 (the int 0))
@@ -189,4 +189,4 @@
)
)
)
)
@@ -1,7 +1,7 @@
(defun stack-test ()
(let ((arr (new 'stack 'array 'uint8 12)))
(let ((arr (new 'stack-no-clear 'array 'uint8 12)))
(logand #b1111 (the uint (&-> arr 3)))
)
)
(stack-test)
(stack-test)
@@ -1,4 +1,4 @@
(let* ((x (new 'stack 'array 'int8 1))
(let* ((x (new 'stack-no-clear 'array 'int8 1))
(x-addr (the uint x)))
(if (and (> x-addr #x7ffff00)
(< x-addr #x7ffffff))
@@ -1,9 +1,9 @@
(let ((x (new 'stack 'array 'int32 1))
(y (new 'stack 'array 'int8 2))
(z (new 'stack 'array 'int8 1)))
(let ((x (new 'stack-no-clear 'array 'int32 1))
(y (new 'stack-no-clear 'array 'int8 2))
(z (new 'stack-no-clear 'array 'int8 1)))
(set! (-> x) 10)
(set! (-> z) 0)
(set! (-> y) #xfffffffff)
(set! (-> y 1) 3)
(+ (-> x) (-> y) (-> z) (-> y 1))
)
)
@@ -2,8 +2,8 @@
(start-test "approx-pi-stack")
(defun test-approx-pi-stack ((res integer))
(let ((rad (new 'stack 'array 'int32 1))
(count (new 'stack 'array 'uint32 1)))
(let ((rad (new 'stack-no-clear 'array 'int32 1))
(count (new 'stack-no-clear 'array 'uint32 1)))
(set! (-> rad) (* res res))
(set! (-> count) 0)
@@ -26,11 +26,11 @@
(defun test-approx-pi-float-stack ((res float))
(let* ((rad (new 'stack 'array 'float 1))
(count (new 'stack 'array 'float 1))
(x (new 'stack 'array 'float 1))
(y (new 'stack 'array 'float 1))
(scale (new 'stack 'array 'float 1)))
(let* ((rad (new 'stack-no-clear 'array 'float 1))
(count (new 'stack-no-clear 'array 'float 1))
(x (new 'stack-no-clear 'array 'float 1))
(y (new 'stack-no-clear 'array 'float 1))
(scale (new 'stack-no-clear 'array 'float 1)))
(set! (-> rad) (* res res))
(set! (-> count) 0.0)
(set! (-> x) 0.0)
@@ -56,4 +56,4 @@
(expect-true (< approx-pi 3.15))
)
(finish-test)
(finish-test)
@@ -38,7 +38,7 @@
(ens test-enum 12))
)
(let ((obj (new 'stack 'enum-bitfield-test-type)))
(let ((obj (new 'stack-no-clear 'enum-bitfield-test-type)))
(format #t "bitfield spacing: ~d~%" (&- (&-> obj bf1) (&-> obj bf0)))
(format #t "enum spacing: ~d~%" (&- (&-> obj en1) (&-> obj en0)))
(format #t "bitfield array spacing: ~d~%" (&- (&-> obj bfs 1) (&-> obj bfs 0)))
@@ -46,7 +46,7 @@
)
(defun function-enum-test ((x test-enum))
(let ((obj (new 'stack 'enum-bitfield-test-type)))
(let ((obj (new 'stack-no-clear 'enum-bitfield-test-type)))
(set! (-> obj en0) x)
(set! (-> obj ens 1) x)
)
@@ -54,15 +54,15 @@
)
(defun function-bitfield-test ((x test-bitfield))
(let ((obj (new 'stack 'enum-bitfield-test-type)))
(let ((obj (new 'stack-no-clear 'enum-bitfield-test-type)))
(set! (-> obj bf0) x)
(set! (-> obj bfs 1) x)
)
(new 'static 'test-bitfield :f1 1)
)
(let ((obj (new 'stack 'enum-bitfield-test-type))
(mem (new 'stack 'array 'uint8 12))
(let ((obj (new 'stack-no-clear 'enum-bitfield-test-type))
(mem (new 'stack-no-clear 'array 'uint8 12))
)
(set! (-> obj bf0) (function-bitfield-test (new 'static 'test-bitfield :f1 1)))
(set! (-> obj bf0) (function-bitfield-test (the test-bitfield 1)))
@@ -77,4 +77,4 @@
)
(format #t "sizes: ~d ~d~%" (size-of test-enum) (size-of test-bitfield))
(format #t "sizes: ~d ~d~%" (size-of test-enum) (size-of test-bitfield))
@@ -11,7 +11,7 @@
)
(defun test-print-sound-name-chars ((arg0 int) (name sound-name) (arg2 int))
(let ((mem (new 'stack 'array 'uint8 16)))
(let ((mem (new 'stack-no-clear 'array 'uint8 16)))
(set! (-> (the (pointer sound-name) mem)) name)
(let ((i 0))
(while (and (< i 16) (nonzero? (-> mem i)))
@@ -13,7 +13,7 @@
(sync *load-str-rpc* '#t)
(let* ((got-length (new 'stack 'array 'int32 1))
(let* ((got-length (new 'stack-no-clear 'array 'int32 1))
(status (str-load-status got-length)))
;(format #t "Status is ~A, length ~D~%" status (-> got-length))
@@ -41,4 +41,4 @@
(expect-true (= 5 (length (-> text data 1 text))))
)
(finish-test)
(finish-test)
@@ -20,8 +20,8 @@
result
)
(let ((arr (new 'stack 'array 'uint8 128))
(arr2 (new 'stack 'array 'uint8 128)))
(let ((arr (new 'stack-no-clear 'array 'uint8 128))
(arr2 (new 'stack-no-clear 'array 'uint8 128)))
(dotimes (i 128)
(set! (-> arr i) i)
(set! (-> arr2 (- 127 i)) i)
@@ -46,4 +46,4 @@
(set! x 0)
(set! z y)
z
)
)
@@ -1,7 +1,7 @@
(let ((v1 (new 'stack 'array 'uint8 16))
(v2 (new 'stack 'array 'uint8 16))
(v3 (new 'stack 'array 'uint8 16))
(let ((v1 (new 'stack-no-clear 'array 'uint8 16))
(v2 (new 'stack-no-clear 'array 'uint8 16))
(v3 (new 'stack-no-clear 'array 'uint8 16))
)
;; initialize stack arrays
@@ -1,6 +1,6 @@
(let ((v1 (new 'stack 'array 'uint8 16))
(v2 (new 'stack 'array 'uint8 16))
(v3 (new 'stack 'array 'uint8 16))
(let ((v1 (new 'stack-no-clear 'array 'uint8 16))
(v2 (new 'stack-no-clear 'array 'uint8 16))
(v3 (new 'stack-no-clear 'array 'uint8 16))
)
;; initialize stack arrays
@@ -30,8 +30,8 @@
(print128 v3-quad) (format #t "~%")
)
(let ((s1 (new 'stack 'array 'uint32 4))
(s2 (new 'stack 'array 'uint32 4)))
(let ((s1 (new 'stack-no-clear 'array 'uint32 4))
(s2 (new 'stack-no-clear 'array 'uint32 4)))
(set! (-> s1 0) #xdeadbeef)
(set! (-> s1 1) #x12312323)
(set! (-> s1 2) #x11112222)
@@ -52,8 +52,8 @@
)
)
(let ((s1 (new 'stack 'array 'uint32 4))
(s2 (new 'stack 'array 'uint32 4)))
(let ((s1 (new 'stack-no-clear 'array 'uint32 4))
(s2 (new 'stack-no-clear 'array 'uint32 4)))
(set! (-> s1 0) #x300)
(set! (-> s1 1) #x3)
(set! (-> s1 2) #x100)
@@ -3,7 +3,7 @@
;; note - this makes some assumptions about how the OpenGOAL compiler will lay things out
;; on the stack.
(let ((x (new 'stack 'array 'uint8 (size-of dma-bucket)))
(y (new 'stack 'array 'uint 1)))
(let ((x (new 'stack-no-clear 'array 'uint8 (size-of dma-bucket)))
(y (new 'stack-no-clear 'array 'uint 1)))
(format #t "size of stack array is ~d~%" (&- y x))
)
@@ -0,0 +1,13 @@
(defun test-stack-inline-array ()
(let ((t0 (new 'stack-no-clear 'array 'int32 1))
(ta (new 'stack-no-clear 'array 'int32 1))
(t1 (new 'stack-no-clear 'inline-array 'vector 3))
(t2 (new 'stack-no-clear 'inline-array 'vector 2)))
;; these are somewhat specific to the current strategy for laying out the stack.
(format #t "#x~X~%" (&- t1 ta))
(format #t "#x~X~%" (&- t2 t1))
(set! (-> t1 1 quad) (the-as uint128 0))
)
)
(test-stack-inline-array)
@@ -42,8 +42,8 @@
(format #t "~%")
;; vector-sin-rad!
(let ((in (new 'stack 'vector))
(out (new 'stack 'vector))
(let ((in (new 'stack-no-clear 'vector))
(out (new 'stack-no-clear 'vector))
)
(set-vector! in PI_OVER_6 (- PI_OVER_4) PI_OVER_3 (- PI_OVER_2))
(vector-sin-rad! out in)
@@ -59,8 +59,8 @@
(format #t "~%")
;; vector-cos-rad!
(let ((in (new 'stack 'vector))
(out (new 'stack 'vector))
(let ((in (new 'stack-no-clear 'vector))
(out (new 'stack-no-clear 'vector))
)
(set-vector! in PI_OVER_6 (- PI_OVER_4) PI_OVER_3 (- PI_OVER_2))
(vector-cos-rad! out in)
@@ -69,9 +69,9 @@
(format #t "~%")
;; vector-sincos-rad!
(let ((in (new 'stack 'vector))
(out-sin (new 'stack 'vector))
(out-cos (new 'stack 'vector))
(let ((in (new 'stack-no-clear 'vector))
(out-sin (new 'stack-no-clear 'vector))
(out-cos (new 'stack-no-clear 'vector))
)
(set-vector! in PI_OVER_6 (- PI_OVER_4) PI_OVER_3 (- PI_OVER_2))
(vector-sincos-rad! out-sin out-cos in)
@@ -81,7 +81,7 @@
(format #t "~%")
;; sincos-rad! (has cosine bug)
(let ((out (new 'stack 'array 'float 2)))
(let ((out (new 'stack-no-clear 'array 'float 2)))
(sincos-rad! out PI_OVER_4)
(format #t "~f ~f~%" (-> out 0) (-> out 1))
(sincos-rad! out (- PI_OVER_2))
@@ -91,7 +91,7 @@
;; sincos! (has cosine bug)
(format #t "sincos!~%")
(let ((out (new 'stack 'array 'float 2)))
(let ((out (new 'stack-no-clear 'array 'float 2)))
(sincos! out (+ 0.0 (degrees 765)))
(format #t "~f ~f~%" (-> out 0) (-> out 1))
(sincos! out (+ (degrees 750) -0.0))
+6
View File
@@ -816,6 +816,12 @@ TEST_F(WithGameTests, PandPorPnor) {
"#x0200000c0a0808080200000402000000\n0\n"});
}
TEST_F(WithGameTests, StackInlineArray) {
runner.run_static_test(env, testCategory, "test-stack-inline-array.gc",
{"#x8\n"
"#x30\n0\n"});
}
TEST(TypeConsistency, TypeConsistency) {
Compiler compiler;
compiler.enable_throw_on_redefines();