1 /************************************************************************
2  ************************************************************************
3     FAUST compiler
4     Copyright (C) 2003-2018 GRAME, Centre National de Creation Musicale
5     ---------------------------------------------------------------------
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  ************************************************************************
20  ************************************************************************/
21 
22 #ifndef _STRUCT_MANAGER_H
23 #define _STRUCT_MANAGER_H
24 
25 #include <string>
26 #include <utility>
27 #include <vector>
28 
29 #include "instructions.hh"
30 
31 // Describe a field memory location in the DSP structure
32 struct MemoryDesc {
33     int fIndex;         // Field index
34     int fOffset;        // Field offset in bytes in a mixed int/real zone
35     int fIntOffset;     // Field offset in bytes in a separated int zone
36     int fRealOffset;    // Field offset in bytes in a separated real zone
37     int fSize;          // Field size in bytes
38 
39     Typed::VarType fType;
40 
MemoryDescMemoryDesc41     MemoryDesc() : fIndex(-1), fOffset(-1), fIntOffset(-1), fRealOffset(-1), fSize(-1), fType(Typed::kNoType) {}
42 
MemoryDescMemoryDesc43     MemoryDesc(int index, int offset, int size, Typed::VarType type)
44     : fIndex(index), fOffset(offset), fIntOffset(-1), fRealOffset(-1), fSize(size), fType(type) {}
45 
MemoryDescMemoryDesc46     MemoryDesc(int index, int offset, int int_offset, int read_offset, int size, Typed::VarType type)
47     : fIndex(index), fOffset(offset), fIntOffset(int_offset), fRealOffset(read_offset), fSize(size), fType(type) {}
48 
getTypedMemoryDesc49     Typed* getTyped()
50     {
51         if (fSize > 1) {
52             return InstBuilder::genArrayTyped(InstBuilder::genBasicTyped(fType), fSize);
53         } else {
54             return InstBuilder::genBasicTyped(fType);
55         }
56     }
57 };
58 
59 /*
60  Compute all field info, the DSP size, and separate 'int' and 'real' types
61  */
62 struct StructInstVisitor : public DispatchVisitor {
63     int        fStructIntOffset;    // Keep the int offset in bytes
64     int        fStructRealOffset;   // Keep the real offset in bytes
65     int        fFieldIndex;         // Keep the field index
66     MemoryDesc fDefault;
67 
68     // Vector is used so that field names are ordered in 'getStructType'
69     typedef vector<pair<string, MemoryDesc> > field_table_type;
70 
71     field_table_type fFieldTable;  // Table: field_name, { index, offset, size, type }
72 
StructInstVisitorStructInstVisitor73     StructInstVisitor() : fStructIntOffset(0), fStructRealOffset(0), fFieldIndex(0) {}
74 
75     // Check if the field name exists
hasFieldStructInstVisitor76     bool hasField(const string& name, Typed::VarType& type)
77     {
78         for (const auto& field : fFieldTable) {
79             if (field.first == name) {
80                 type = field.second.fType;
81                 return true;
82             }
83         }
84         return false;
85     }
86 
87     // Return the offset of a given field in bytes
getFieldOffsetStructInstVisitor88     int getFieldOffset(const string& name)
89     {
90         for (const auto& field : fFieldTable) {
91             if (field.first == name) return field.second.fOffset;
92         }
93         std::cerr << "ERROR in getFieldOffset : " << name << std::endl;
94         faustassert(false);
95         return -1;
96     }
97 
98     // Return the int offset of a given field in bytes
getFieldIntOffsetStructInstVisitor99     int getFieldIntOffset(const string& name)
100     {
101         for (const auto& field : fFieldTable) {
102             if (field.first == name) return field.second.fIntOffset;
103         }
104         std::cerr << "ERROR in getFieldIntOffset : " << name << std::endl;
105         faustassert(false);
106         return -1;
107     }
108 
109     // Return the real offset of a given field in bytes
getFieldRealOffsetStructInstVisitor110     int getFieldRealOffset(const string& name)
111     {
112         for (const auto& field : fFieldTable) {
113             if (field.first == name) return field.second.fRealOffset;
114         }
115         std::cerr << "ERROR in getFieldRealOffset : " << name << std::endl;
116         faustassert(false);
117         return -1;
118     }
119 
120     // Return the index of a given field
getFieldIndexStructInstVisitor121     int getFieldIndex(const string& name)
122     {
123         for (const auto& field : fFieldTable) {
124             if (field.first == name) return field.second.fIndex;
125         }
126         std::cerr << "ERROR in getFieldIndex : " << name << std::endl;
127         faustassert(false);
128         return -1;
129     }
130 
131     // Return the memory description of a given field
getMemoryDescStructInstVisitor132     MemoryDesc& getMemoryDesc(const string& name)
133     {
134         for (auto& field : fFieldTable) {
135             if (field.first == name) return field.second;
136         }
137         std::cerr << "ERROR in getMemoryDesc : " << name << std::endl;
138         faustassert(false);
139         return fDefault;
140     }
141 
142     // Return the struct 'int' size in bytes
getStructIntSizeStructInstVisitor143     int getStructIntSize() { return fStructIntOffset; }
144 
145     // Return the struct 'real' size in bytes
getStructRealSizeStructInstVisitor146     int getStructRealSize() { return fStructRealOffset; }
147 
148     // Return the struct size in bytes
getStructSizeStructInstVisitor149     int getStructSize() { return fStructIntOffset + fStructRealOffset; }
150 
getFieldTableStructInstVisitor151     field_table_type& getFieldTable() { return fFieldTable; }
152 
153     // Return the struct type
getStructTypeStructInstVisitor154     DeclareStructTypeInst* getStructType(const string& name)
155     {
156         vector<NamedTyped*> dsp_type_fields;
157         for (auto& field : fFieldTable) {
158             // std::cout << "getStructType " << field.first << std::endl;
159             dsp_type_fields.push_back(InstBuilder::genNamedTyped(field.first, field.second.getTyped()));
160         }
161         return InstBuilder::genDeclareStructTypeInst(InstBuilder::genStructTyped(name, dsp_type_fields));
162     }
163 
164     // Declarations
visitStructInstVisitor165     virtual void visit(DeclareVarInst* inst)
166     {
167         //dump2FIR(inst);
168         string              name   = inst->fAddress->getName();
169         Address::AccessType access = inst->fAddress->getAccess();
170 
171         bool        is_struct   = (access & Address::kStruct) || (access & Address::kStaticStruct);
172         ArrayTyped* array_typed = dynamic_cast<ArrayTyped*>(inst->fType);
173 
174         if (array_typed && array_typed->fSize > 1) {
175             if (is_struct) {
176                 fFieldTable.push_back(make_pair(name, MemoryDesc(fFieldIndex++,
177                                                                  getStructSize(),
178                                                                  getStructIntSize(),
179                                                                  getStructRealSize(),
180                                                                  array_typed->fSize,
181                                                                  array_typed->fType->getType())));
182                 if (array_typed->fType->getType() == Typed::kInt32) {
183                     fStructIntOffset += array_typed->getSize();
184                 } else {
185                     fStructRealOffset += array_typed->getSize();
186                 }
187             } else {
188                 // Should never happen...
189                 faustassert(false);
190             }
191         } else {
192             if (is_struct) {
193                 fFieldTable.push_back(make_pair(name, MemoryDesc(fFieldIndex++,
194                                                                  getStructSize(),
195                                                                  getStructIntSize(),
196                                                                  getStructRealSize(),
197                                                                  1, inst->fType->getType())));
198                 if (inst->fType->getType() == Typed::kInt32) {
199                     fStructIntOffset += inst->fType->getSize();
200                 } else {
201                     fStructRealOffset += inst->fType->getSize();
202                 }
203             } else {
204                 // Local variables declared by [var_num, type] pairs
205                 faustassert(inst->fValue == nullptr);
206             }
207         }
208     }
209 
210 };
211 
212 #endif
213