PageRenderTime 45ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/src/xf/nucleus/kdef/KDefProcessor.d

https://bitbucket.org/h3r3tic/boxen
D | 882 lines | 686 code | 162 blank | 34 comment | 116 complexity | 3400da440c64b57863d50e6708197f95 MD5 | raw file
  1. module xf.nucleus.kdef.KDefProcessor;
  2. private {
  3. import tango.core.Tuple;
  4. import
  5. xf.nucleus.kdef.model.IKDefFileParser,
  6. xf.nucleus.kdef.model.KDefInvalidation,
  7. xf.nucleus.kdef.KDefParserBase,
  8. xf.nucleus.kdef.Common,
  9. xf.nucleus.kdef.ParamUtils;
  10. import
  11. xf.nucleus.kernel.KernelDef;
  12. import
  13. xf.nucleus.Defs,
  14. xf.nucleus.TypeSystem,
  15. xf.nucleus.TypeConversion,
  16. xf.nucleus.Function,
  17. xf.nucleus.Param,
  18. xf.nucleus.Value,
  19. xf.nucleus.KernelImpl,
  20. xf.nucleus.SurfaceDef,
  21. xf.nucleus.MaterialDef,
  22. Dep = xf.nucleus.DepTracker;
  23. import
  24. xf.mem.ScratchAllocator,
  25. xf.mem.StackBuffer,
  26. xf.mem.Gather;
  27. import xf.utils.Graph : findTopologicalOrder, CycleHandlingMode;
  28. import xf.utils.Memory : alloc, free, append;
  29. import xf.nucleus.Log : error = nucleusError, log = nucleusLog;
  30. import tango.io.Stdout; // for dumpInfo, could be moved outside, to another mod
  31. import tango.io.vfs.model.Vfs;
  32. alias char[] string;
  33. }
  34. class KDefProcessor {
  35. alias DgScratchAllocator Allocator;
  36. this (IKDefFileParser fileParser) {
  37. this.fileParser = fileParser;
  38. }
  39. static Allocator modAlloc(KDefModule mod) {
  40. return mod.mem;
  41. }
  42. void processFile(string path) {
  43. if (auto mod = path in _modules) {
  44. if ((*mod).processing) {
  45. throw new Exception("Cyclic import in kernel module '" ~ path ~ "'");
  46. }
  47. } else {
  48. log.trace("KDefProcessor.parseFile({})", path);
  49. auto mod = fileParser.parseFile(path);
  50. _modules[path] = mod;
  51. mod.processing = true;
  52. mod.filePath = path;
  53. process(mod, modAlloc(mod));
  54. mod.processing = false;
  55. }
  56. }
  57. KDefModule getModuleForPath(string path) {
  58. if (auto mod = path in _modules) {
  59. return *mod;
  60. } else {
  61. return null;
  62. }
  63. }
  64. void doSemantics() {
  65. doKernelSemantics();
  66. }
  67. void dispose() {
  68. foreach (ref mod; _modules) {
  69. delete mod;
  70. }
  71. // TODO(?): do more thorough cleaning
  72. _modules = null;
  73. }
  74. void dumpInfo() {
  75. Stdout.formatln("got {} modules:", _modules.keys.length);
  76. foreach (name, mod; _modules) {
  77. Stdout.formatln("mod {}:", name);
  78. dumpInfo(mod);
  79. }
  80. }
  81. struct KernelInfo {
  82. KernelImpl* impl;
  83. KDefModule mod;
  84. }
  85. KernelInfo[string] kernels;
  86. int converters(int delegate(ref SemanticConverter) dg) {
  87. foreach (name, mod; _modules) {
  88. foreach (ref conv; mod.converters) {
  89. if (auto r = dg(conv)) {
  90. return r;
  91. }
  92. }
  93. }
  94. return 0;
  95. }
  96. KernelImpl getKernel(string name) {
  97. if (auto impl = name in this.kernels) {
  98. return *impl.impl;
  99. } else {
  100. error("Unknown kernel: '{}'.", name);
  101. assert (false);
  102. }
  103. }
  104. // BUG: this is slow
  105. KernelImpl getKernel(KernelImplId id) {
  106. assert (id.isValid);
  107. foreach (k, ref v; this.kernels) {
  108. assert (v.impl.id.isValid);
  109. if (v.impl.id == id) {
  110. return *v.impl;
  111. }
  112. }
  113. error("Unknown kernel id: '{}'.", id.value);
  114. assert (false);
  115. }
  116. bool getKernel(string name, KernelImpl* res) {
  117. if (auto impl = name in this.kernels) {
  118. *res = *impl.impl;
  119. return true;
  120. } else {
  121. return false;
  122. }
  123. }
  124. int kernelImpls(int delegate(ref KernelImpl) dg) {
  125. foreach (n, k; this.kernels) {
  126. if (int r = dg(*k.impl)) {
  127. return r;
  128. }
  129. }
  130. return 0;
  131. }
  132. int surfaces(int delegate(ref string, ref SurfaceDef) dg) {
  133. foreach (name, mod; _modules) {
  134. foreach (name, ref surf; mod.surfaces) {
  135. string meh = name;
  136. if (auto r = dg(meh, surf)) {
  137. return r;
  138. }
  139. }
  140. }
  141. return 0;
  142. }
  143. int materials(int delegate(ref string, ref MaterialDef) dg) {
  144. foreach (name, mod; _modules) {
  145. foreach (name, ref surf; mod.materials) {
  146. string meh = name;
  147. if (auto r = dg(meh, surf)) {
  148. return r;
  149. }
  150. }
  151. }
  152. return 0;
  153. }
  154. int modules(int delegate(ref string, ref KDefModule) dg) {
  155. foreach (name, mod; _modules) {
  156. if (int r = dg(name, mod)) {
  157. return r;
  158. }
  159. }
  160. return 0;
  161. }
  162. KDefInvalidationInfo invalidateDifferences(KDefProcessor other) {
  163. KDefInvalidationInfo res;
  164. foreach (modName, mod; other._modules) {
  165. if (!(modName in this._modules)) {
  166. if (mod.converters.length > 0) {
  167. res.anyConverters = true;
  168. }
  169. }
  170. }
  171. foreach (modName, mod; _modules) {
  172. if (auto otherMod = modName in other._modules) {
  173. foreach (name, ref o; mod.kernels) {
  174. if (auto o2 = name in otherMod.kernels) {
  175. if (o != *o2) {
  176. o.invalidate();
  177. }
  178. } else {
  179. o.invalidate();
  180. }
  181. }
  182. foreach (name, ref o; mod.surfaces) {
  183. if (auto o2 = name in otherMod.surfaces) {
  184. if (o != *o2) {
  185. o.invalidate();
  186. }
  187. } else {
  188. o.invalidate();
  189. }
  190. }
  191. foreach (name, ref o; mod.materials) {
  192. if (auto o2 = name in otherMod.materials) {
  193. if (o != *o2) {
  194. o.invalidate();
  195. }
  196. } else {
  197. o.invalidate();
  198. }
  199. }
  200. if (!res.anyConverters) {
  201. if (mod.converters.length != otherMod.converters.length) {
  202. res.anyConverters = true;
  203. } else {
  204. foreach (i, ref c; mod.converters) {
  205. if (c != otherMod.converters[i]) {
  206. res.anyConverters = true;
  207. break;
  208. }
  209. }
  210. }
  211. }
  212. } else {
  213. // If the module is missing from the other processor,
  214. // invalidate all of the current module's items
  215. if (mod.converters.length > 0) {
  216. res.anyConverters = true;
  217. }
  218. foreach (name, ref o; mod.kernels) {
  219. o.invalidate();
  220. }
  221. foreach (name, ref o; mod.surfaces) {
  222. o.invalidate();
  223. }
  224. foreach (name, ref o; mod.materials) {
  225. o.invalidate();
  226. }
  227. }
  228. }
  229. Dep.invalidateGraph((void delegate(Dep.DepTracker*) depSink) {
  230. void process(Dep.DepTracker* tr) {
  231. if (!tr.valid) {
  232. depSink(tr);
  233. }
  234. }
  235. foreach (modName, mod; _modules) {
  236. foreach (name, ref o; mod.kernels) {
  237. process(o.dependentOnThis);
  238. }
  239. foreach (name, ref o; mod.surfaces) {
  240. process(o.dependentOnThis);
  241. }
  242. foreach (name, ref o; mod.materials) {
  243. process(o.dependentOnThis);
  244. }
  245. }
  246. });
  247. return res;
  248. }
  249. private {
  250. enum Processed {
  251. Not,
  252. InProgress,
  253. Done
  254. }
  255. void doKernelSemantics() {
  256. Processed[KernelImpl] processed;
  257. foreach (name, mod; _modules) {
  258. foreach (kname, ref kimpl; mod.kernels) {
  259. if (kname in this.kernels) {
  260. error(
  261. "Multiple definitions of kernel '{}' in:\n {}\n and\n {}.",
  262. kname,
  263. mod.filePath,
  264. this.kernels[kname].mod.filePath
  265. );
  266. } else {
  267. this.kernels[kname] = KernelInfo(
  268. &kimpl,
  269. mod
  270. );
  271. }
  272. if (KernelImpl.Type.Kernel == kimpl.type) {
  273. if (auto func = cast(Function)kimpl.kernel.func) {
  274. static assert (is(typeof(mod) == KDefModule));
  275. func.code._module = cast(void*)mod;
  276. }
  277. kimpl.kernel._module = cast(void*)mod;
  278. } else {
  279. GraphDef(kimpl.graph)._module = cast(void*)mod;
  280. }
  281. }
  282. }
  283. foreach (name, mod; _modules) {
  284. foreach (ref surf; mod.surfaces) {
  285. getKernel(surf.reflKernelName)
  286. .dependentOnThis.add(surf.dependentOnThis);
  287. }
  288. foreach (ref mat; mod.materials) {
  289. getKernel(mat.materialKernelName)
  290. .dependentOnThis.add(mat.dependentOnThis);
  291. }
  292. }
  293. foreach (n, ref k; kernels) {
  294. _curSemModule = k.mod;
  295. doKernelSemantics(*k.impl, modAlloc(k.mod), processed);
  296. }
  297. }
  298. void inheritKernel(KernelDef sub, KernelImpl supr) {
  299. iterKernelInputs(supr, (Param* p) {
  300. if (!sub.func.params.get(p.name)) {
  301. sub.func.params.add(*p);
  302. }
  303. });
  304. iterKernelOutputs(supr, (Param* p) {
  305. if (!sub.func.params.get(p.name)) {
  306. sub.func.params.add(*p);
  307. }
  308. });
  309. }
  310. void getPlainSemanticForNode(Param* par, Semantic* plainSem, KernelImpl supr) {
  311. findOutputSemantic(
  312. par,
  313. // getFormalParamSemantic
  314. (string name) {
  315. Semantic* res;
  316. iterKernelInputs(supr, (Param* p) {
  317. if (p.isInput && p.name == name) {
  318. res = p.semantic();
  319. }
  320. });
  321. if (res) {
  322. return *res;
  323. }
  324. error(
  325. "simplifyParamSemantics: output param '{}' refers to a"
  326. " nonexistent formal parameter '{}'.",
  327. par.name,
  328. name
  329. );
  330. assert (false);
  331. },
  332. // getActualParamSemantic
  333. (string name) {
  334. error(
  335. "Cannot derive node params from {}: param {} has a semantic expression.",
  336. supr.name,
  337. par.name
  338. );
  339. return Semantic.init;
  340. },
  341. plainSem
  342. );
  343. }
  344. void inheritKernelInputs(GraphDefNode node, KernelImpl supr) {
  345. iterKernelInputs(supr, (Param* p) {
  346. if (!node.params.get(p.name)) {
  347. assert (p.hasPlainSemantic);
  348. node.params.add(*p).dir = ParamDirection.Out;
  349. }
  350. });
  351. }
  352. void inheritKernelOutputs(GraphDefNode node, KernelImpl supr) {
  353. iterKernelOutputs(supr, (Param* p) {
  354. if (!node.params.get(p.name)) {
  355. if (!p.hasPlainSemantic) {
  356. auto pnew = node.params.add(ParamDirection.In, p.name);
  357. pnew.hasPlainSemantic = true;
  358. getPlainSemanticForNode(p, pnew.semantic, supr);
  359. pnew.copyValueFrom(p);
  360. pnew.annotation = p.annotation;
  361. } else {
  362. node.params.add(*p).dir = ParamDirection.In;
  363. }
  364. }
  365. });
  366. }
  367. void iterKernelParams(
  368. KernelImpl impl,
  369. bool wantInputs,
  370. void delegate(Param*) sink
  371. ) {
  372. switch (impl.type) {
  373. case KernelImpl.Type.Kernel: {
  374. foreach (ref p; impl.kernel.func.params) {
  375. if (wantInputs == p.isInput) {
  376. sink(&p);
  377. }
  378. }
  379. } break;
  380. case KernelImpl.Type.Graph: {
  381. foreach (nodeName, node; GraphDef(impl.graph).nodes) {
  382. if ((wantInputs ? "input" : "output") == node.type) {
  383. foreach (ref p; node.params) {
  384. sink(&p);
  385. }
  386. }
  387. }
  388. } break;
  389. default: assert (false);
  390. }
  391. }
  392. void iterKernelInputs(KernelImpl impl, void delegate(Param*) sink) {
  393. iterKernelParams(impl, true, sink);
  394. }
  395. void iterKernelOutputs(KernelImpl impl, void delegate(Param*) sink) {
  396. iterKernelParams(impl, false, sink);
  397. }
  398. void doKernelSemantics(ref KernelDef k, Allocator allocator, ref Processed[KernelImpl] processed) {
  399. if (k.superKernel.length > 0) {
  400. auto superKernel = getKernel(k.superKernel);
  401. doKernelSemantics(superKernel, allocator, processed);
  402. inheritKernel(k, superKernel);
  403. superKernel.dependentOnThis.add(
  404. k.dependentOnThis
  405. );
  406. }
  407. }
  408. void doKernelSemantics(GraphDef graph, Allocator allocator, ref Processed[KernelImpl] processed) {
  409. KernelImpl superKernel;
  410. if (graph.superKernel.length > 0) {
  411. superKernel = getKernel(graph.superKernel);
  412. doKernelSemantics(superKernel, allocator, processed);
  413. superKernel.dependentOnThis.add(
  414. graph.dependentOnThis
  415. );
  416. }
  417. foreach (nodeName, node; graph.nodes) {
  418. switch (node.type) {
  419. case "input": {
  420. if (!superKernel.isNull) {
  421. inheritKernelInputs(node, superKernel);
  422. }
  423. } break;
  424. case "output": {
  425. if (!superKernel.isNull) {
  426. inheritKernelOutputs(node, superKernel);
  427. }
  428. } break;
  429. case "kernel": {
  430. auto kernelVar = node.getVar("kernel");
  431. if (kernelVar is null) {
  432. // TODO: err
  433. error("No kernel defined for a kernel node.");
  434. }
  435. if (auto ident = cast(IdentifierValue)kernelVar) {
  436. node.kernelImpl = getKernel(ident.value);
  437. }
  438. else if (auto literal = cast(KernelDefValue)kernelVar) {
  439. if (!cast(Function)literal.kernelDef.func) {
  440. // TODO: err
  441. error(
  442. "Graph nodes must use concrete kernel literals."
  443. );
  444. }
  445. doKernelSemantics(literal.kernelDef, allocator, processed);
  446. node.kernelImpl = KernelImpl(literal.kernelDef);
  447. node.kernelImpl.kernel.func.name = "literal";
  448. node.kernelImpl.kernel._module = cast(void*)_curSemModule;
  449. }
  450. else {
  451. error(
  452. "The 'kernel' var in a graph node must be"
  453. " either an identifier or a concrete kernel literal,"
  454. " not a '{}'", kernelVar.classinfo.name
  455. );
  456. }
  457. node.kernelImpl.dependentOnThis.add(
  458. graph.dependentOnThis
  459. );
  460. } break;
  461. default: break;
  462. }
  463. }
  464. }
  465. void doKernelSemantics(ref KernelImpl k, Allocator allocator, ref Processed[KernelImpl] processed) {
  466. if (auto p = k in processed) {
  467. switch (*p) {
  468. case Processed.InProgress: {
  469. char[] list;
  470. foreach (ki, p2; processed) {
  471. if (Processed.InProgress == p2) {
  472. list ~= " '"~ki.name~"'\n";
  473. }
  474. }
  475. // TODO: keep track of the exact eval order
  476. error(
  477. "Recursive prosessing of a kernel '{}'. From:\n{}",
  478. k.name,
  479. list
  480. );
  481. } break;
  482. case Processed.Not: break;
  483. case Processed.Done: return;
  484. default: assert (false);
  485. }
  486. }
  487. processed[k] = Processed.InProgress;
  488. scope (success) processed[k] = Processed.Done;
  489. switch (k.type) {
  490. case KernelImpl.Type.Kernel: {
  491. doKernelSemantics(k.kernel, allocator, processed);
  492. } break;
  493. case KernelImpl.Type.Graph: {
  494. doKernelSemantics(GraphDef(k.graph), allocator, processed);
  495. } break;
  496. default: assert (false);
  497. }
  498. }
  499. // --------------------------------------------------------------------------------------------------------------------------------
  500. //
  501. struct SimpleArray(T) {
  502. private {
  503. T[] _arr;
  504. size_t _len;
  505. }
  506. size_t length() {
  507. return _len;
  508. }
  509. T[] data() {
  510. return _arr[0.._len];
  511. }
  512. void add(T t) {
  513. _arr.append(t, &_len);
  514. }
  515. void dispose() {
  516. _arr.free();
  517. }
  518. }
  519. void dispose2dArray(T)(ref SimpleArray!(T)[] arr) {
  520. foreach (ref item; arr) {
  521. item.dispose();
  522. }
  523. arr.free();
  524. }
  525. //
  526. // --------------------------------------------------------------------------------------------------------------------------------
  527. void dumpInfo(KDefModule mod) {
  528. Stdout.formatln("* path: {}", mod.filePath);
  529. Stdout.formatln("* kernel impls:");
  530. foreach (n, impl; mod.kernels) {
  531. dumpInfo(impl);
  532. }
  533. }
  534. void dumpInfo(KernelImpl kimpl) {
  535. switch (kimpl.type) {
  536. case KernelImpl.Type.Graph:
  537. return dumpInfo(GraphDef(kimpl.graph));
  538. case KernelImpl.Type.Kernel:
  539. return dumpInfo(kimpl.kernel);
  540. default: assert (false);
  541. }
  542. }
  543. void dumpInfo(AbstractFunction func) {
  544. Stdout.formatln("\tfunc: {} {{", func.name);
  545. foreach (param; func.params) {
  546. Stdout.format("\t\t{}", param);
  547. /+if (param.defaultValue) {
  548. Stdout.formatln(" = {}", param.defaultValue);
  549. }+/
  550. Stdout.newline;
  551. }
  552. if (auto qf = cast(Function)func) {
  553. //Stdout.formatln("{} code:", qf.code.language);
  554. Stdout("----").newline;
  555. char[] code;
  556. qf.code.writeOut((char[] s) {
  557. code ~= s;
  558. });
  559. Stdout(code).newline;
  560. Stdout("----").newline;
  561. }
  562. Stdout("}").newline;
  563. }
  564. void dumpInfo(GraphDef graph) {
  565. Stdout("graph {").newline;
  566. Stdout.formatln("file: {}", (cast(KDefModule)graph._module).filePath);
  567. Stdout.formatln("bytes: {}..{}", graph._firstByte, graph._firstByte + graph._lengthBytes);
  568. foreach (nodeName, _node; graph.nodes) {
  569. Stdout.formatln("\tnode: {}", nodeName);
  570. }
  571. /+foreach (graphName, subGraph; graph.graphs) {
  572. Stdout.formatln("\tsub-graph: ");
  573. dumpInfo(subGraph);
  574. }+/
  575. Stdout("}").newline;
  576. }
  577. void dumpInfo(KernelDef kernel) {
  578. dumpInfo(kernel.func);
  579. }
  580. void process(Scope sc, Allocator allocator) {
  581. gatherArrays!(string, Value)(sc.mem,
  582. (void delegate(lazy string, lazy Value) gen) {
  583. foreach (stmt_; sc.statements) {
  584. if (auto stmt = cast(AssignStatement)stmt_) {
  585. gen(stmt.name, stmt.value);
  586. }
  587. }
  588. },
  589. (string[] names, Value[] values) {
  590. sc.doAssign(names, values);
  591. });
  592. gatherArrays!(string, string)(sc.mem,
  593. (void delegate(lazy string, lazy string) gen) {
  594. foreach (stmt_; sc.statements) {
  595. if (auto stmt = cast(ConnectStatement)stmt_) {
  596. if (auto graph = cast(GraphDef)sc) {
  597. gen(stmt.from, stmt.to);
  598. } else {
  599. throw new Exception("connections only allowed at graph scope");
  600. }
  601. }
  602. }
  603. },
  604. (string[] from, string[] to) {
  605. (cast(GraphDef)sc).doConnect(from, to);
  606. });
  607. gatherArrays!(string)(sc.mem,
  608. (void delegate(lazy string) gen) {
  609. foreach (stmt_; sc.statements) {
  610. if (auto stmt = cast(NoAutoFlowStatement)stmt_) {
  611. if (auto graph = cast(GraphDef)sc) {
  612. gen(stmt.to);
  613. } else {
  614. error("Can't use noauto outside of graph definitions.");
  615. }
  616. }
  617. }
  618. },
  619. (string[] to) {
  620. (cast(GraphDef)sc).setNoAuto(to);
  621. });
  622. foreach (stmt_; sc.statements) {
  623. if (auto stmt = cast(ConnectStatement)stmt_) {
  624. // nothing
  625. } else if (auto stmt = cast(NoAutoFlowStatement)stmt_) {
  626. // nothing
  627. } else if (auto stmt = cast(AssignStatement)stmt_) {
  628. if (auto scopeValue = cast(IScopeValue)stmt.value) {
  629. process(scopeValue.toScope, allocator);
  630. }
  631. if (auto kernelValue = cast(KernelDefValue)stmt.value) {
  632. kernelValue.kernelDef.func.name = stmt.name;
  633. if (auto mod = cast(KDefModule)sc) {
  634. mod.kernels[stmt.name] = KernelImpl(kernelValue.kernelDef);
  635. }
  636. }
  637. if (auto graphValue = cast(GraphDefValue)stmt.value) {
  638. GraphDef(graphValue.graphDef)._name = stmt.name;
  639. if (auto mod = cast(KDefModule)sc) {
  640. mod.kernels[stmt.name] = KernelImpl(graphValue.graphDef);
  641. }
  642. }
  643. if (auto surfValue = cast(SurfaceDefValue)stmt.value) {
  644. surfValue.surface.name = stmt.name;
  645. if (auto mod = cast(KDefModule)sc) {
  646. mod.surfaces[stmt.name] = surfValue.surface;
  647. }
  648. }
  649. if (auto matValue = cast(MaterialDefValue)stmt.value) {
  650. matValue.material.name = stmt.name;
  651. if (auto mod = cast(KDefModule)sc) {
  652. mod.materials[stmt.name] = matValue.material;
  653. }
  654. }
  655. if (auto nodeValue = cast(GraphDefNodeValue)stmt.value) {
  656. auto node = nodeValue.node;
  657. switch (node.type) {
  658. case "input":
  659. case "data":
  660. case "output": {
  661. node.params = ParamList(allocator._allocator);
  662. }
  663. default: break;
  664. }
  665. buildConcreteParams(node, &node.params);
  666. }
  667. if (auto traitValue = cast(TraitDefValue)stmt.value) {
  668. traitValue.value.name = stmt.name;
  669. if (auto mod = cast(KDefModule)sc) {
  670. mod.traitDefs ~= traitValue.value;
  671. }
  672. }
  673. } else if (auto stmt = cast(ImportStatement)stmt_) {
  674. auto path = stmt.path;
  675. processFile(path);
  676. auto names = stmt.what;
  677. auto mod = _modules[path];
  678. if (names !is null) {
  679. assert (false, "TODO: selective imports");
  680. } else {
  681. sc.doImport((void delegate(Statement) dg) {
  682. foreach (st; mod.statements) {
  683. dg(st);
  684. }
  685. });
  686. }
  687. } else if (auto stmt = cast(ConverterDeclStatement)stmt_) {
  688. if (auto mod = cast(KDefModule)sc) {
  689. assert (2 == stmt.func.params.length); // there's also hidden context
  690. auto from = stmt.func.params[0];
  691. auto to = stmt.func.params[1];
  692. /+if ("Cg" == stmt.func.code.language) {
  693. if (!from.semantic.hasTrait("domain")) {
  694. from.semantic.addTrait("domain", "gpu");
  695. }
  696. if (!to.semantic.hasTrait("domain")) {
  697. to.semantic.addTrait("domain", "gpu");
  698. }
  699. }+/
  700. string name = stmt.func.name;
  701. if (name is null) {
  702. // Will get renamed for overloads by codegen
  703. name = "converter";
  704. }
  705. mod.converters ~= SemanticConverter(stmt.func, stmt.cost);
  706. } else {
  707. throw new Exception("only can has converters at module scope ktnx");
  708. }
  709. } else {
  710. throw new Exception("Unhandled statement: " ~ stmt_.toString);
  711. }
  712. }
  713. }
  714. IKDefFileParser fileParser;
  715. // indexed by path
  716. KDefModule[string] _modules;
  717. KDefModule _curSemModule;
  718. }
  719. }