• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

daisytuner / docc / 22287993212

22 Feb 2026 11:45PM UTC coverage: 64.63% (-0.1%) from 64.743%
22287993212

Pull #537

github

web-flow
Merge d546ea4e1 into d39f6af54
Pull Request #537: Adds memory management to frontend

48 of 51 new or added lines in 4 files covered. (94.12%)

62 existing lines in 4 files now uncovered.

23672 of 36627 relevant lines covered (64.63%)

357.5 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.06
/python/docc/python/memory.py
1
"""Managed memory allocation and deallocation for SDFG code generation."""
2

3

4
class ManagedMemoryHandler:
4✔
5
    """
6
    Handles memory allocation with automatic cleanup.
7

8
    Tracks allocations whose size depends only on function arguments
9
    (hoistable) and emits:
10
    - malloc at scope start (hoisted)
11
    - optional memset for zero init
12
    - free before scope exit
13

14
    Allocations with sizes depending on loop variables are rejected
15
    and must be handled immediately by the caller.
16
    """
17

18
    # Initialization types
19
    INIT_NONE = "none"
4✔
20
    INIT_ZERO = "zero"  # Use memset(0)
4✔
21

22
    def __init__(self, builder):
4✔
23
        self.builder = builder
4✔
24
        self._allocations = []
4✔
25

26
    def allocate(self, name, ptr_type, total_size, init=INIT_NONE):
4✔
27
        """
28
        Try to register an allocation for hoisting.
29

30
        Checks if the size expression depends only on function arguments.
31
        If so, tracks the allocation and returns True. Otherwise returns False
32
        and the caller must emit the allocation immediately.
33

34
        Args:
35
            name: Container name for the pointer
36
            ptr_type: Pointer type (e.g., Pointer(Scalar(PrimitiveType.Float)))
37
            total_size: Size expression in bytes (string)
38
            init: Initialization type (INIT_NONE or INIT_ZERO)
39

40
        Returns:
41
            True if allocation was accepted (hoistable), False otherwise
42
        """
43
        # Check if size is hoistable (depends only on function arguments)
44
        if not self.builder.is_hoistable_size(total_size):
4✔
45
            return False
4✔
46

47
        self._allocations.append(
4✔
48
            {
49
                "name": name,
50
                "ptr_type": ptr_type,
51
                "total_size": total_size,
52
                "init": init,
53
            }
54
        )
55
        return True
4✔
56

57
    def emit_allocations(self):
4✔
58
        """
59
        Emit malloc (and memset for INIT_ZERO) at scope start.
60

61
        Must be called after parsing is complete but before builder.move().
62
        Allocations are emitted in reverse order since insert_block_at_root_start prepends.
63
        """
64
        for alloc in reversed(self._allocations):
4✔
65
            # For INIT_ZERO, insert memset first (will be after malloc due to prepending)
66
            if alloc["init"] == self.INIT_ZERO:
4✔
67
                block = self.builder.insert_block_at_root_start()
4✔
68
                t_memset = self.builder.add_memset(block, "0", alloc["total_size"])
4✔
69
                t_ptr = self.builder.add_access(block, alloc["name"])
4✔
70
                self.builder.add_memlet(
4✔
71
                    block, t_memset, "_ptr", t_ptr, "void", "", alloc["ptr_type"]
72
                )
73

74
            # Insert malloc (will end up before memset)
75
            block = self.builder.insert_block_at_root_start()
4✔
76
            t_malloc = self.builder.add_malloc(block, alloc["total_size"])
4✔
77
            t_ptr = self.builder.add_access(block, alloc["name"])
4✔
78
            self.builder.add_memlet(
4✔
79
                block, t_malloc, "_ret", t_ptr, "void", "", alloc["ptr_type"]
80
            )
81

82
    def emit_frees(self):
4✔
83
        """
84
        Emit free calls for all allocations.
85

86
        Should be called before each return statement.
87
        """
88
        for alloc in self._allocations:
4✔
89
            block = self.builder.add_block()
4✔
90
            t_free = self.builder.add_free(block)
4✔
91
            t_ptr_in = self.builder.add_access(block, alloc["name"])
4✔
92
            t_ptr_out = self.builder.add_access(block, alloc["name"])
4✔
93
            # Input memlet: access_node -> free._ptr
94
            self.builder.add_memlet(
4✔
95
                block, t_ptr_in, "void", t_free, "_ptr", "", alloc["ptr_type"]
96
            )
97
            # Output memlet: free._ptr -> access_node (required for library node)
98
            self.builder.add_memlet(
4✔
99
                block, t_free, "_ptr", t_ptr_out, "void", "", alloc["ptr_type"]
100
            )
101

102
    def has_allocations(self):
4✔
103
        """Check if there are any managed allocations."""
104
        return len(self._allocations) > 0
4✔
105

106
    def clear(self):
4✔
107
        """Clear all tracked allocations."""
NEW
108
        self._allocations.clear()
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc