@@ -18,6 +18,7 @@ import Somac.Alloy.Func
1818import Somac.Circuit.Graph
1919import Somac.Circuit.Node
2020import Soma.Core.Value
21+ import Soma.Core.Name
2122import Soma.Core.Primitive
2223import Std.Data.HashMap
2324import Std.Data.HashSet
@@ -36,6 +37,7 @@ abbrev CLabel := Somac.Circuit.Node.Label
3637abbrev CNodeEntry := Somac.Circuit.Graph.NodeEntry
3738
3839open Somac.Circuit.Term (Op1Code Op2Code PrimType Tag)
40+ open Soma.Core (Name FFIOp Intrinsic)
3941
4042/-- Mapping from Circuit node ports to Alloy local values -/
4143abbrev PortMap := Std.HashMap (Nat × Nat) LocalId
@@ -210,6 +212,21 @@ def convertUnOp : Op1Code → UnOp
210212 | .not => .not
211213 | .neg => .neg
212214
215+ /-- Convert Core FFIOp to Alloy IntrinsicOp -/
216+ def convertFFIOp : FFIOp → IntrinsicOp
217+ | .null => .ptrNull
218+ | .ptrAdd => .ptrAdd
219+ | .ptrDiff => .ptrDiff
220+ | .ptrRead => .ptrRead
221+ | .ptrWrite => .ptrWrite
222+ | .ptrCast => .ptrCast
223+ | .toCString => .toCString
224+ | .fromCString => .fromCString
225+ | .cstringLen => .cstringLen
226+ | .strcat => .strcat
227+ | .intToString => .intToString
228+ | .pureIO => .pureIO
229+
213230open Soma.Core (Value StarPrimitive HigherPrimitive)
214231
215232/-- Convert a StarPrimitive to Alloy PrimTy -/
@@ -318,7 +335,7 @@ partial def convertValueType : Value → Ty
318335 | Value.vTransport _ _ _ _ _ _ _ => .prim .i64 -- Transport carries the value
319336
320337 -- Literals
321- | Value.vIntLit _ => .prim .i64
338+ | Value.vIntLit _ => .prim .i32
322339 | Value.vStringLit _ => .rawPtr
323340
324341/-- Extract type parameters and value parameters from a function type (Pi chain) -/
@@ -353,7 +370,7 @@ def extractReturnType (ty : Value) : Ty :=
353370 | none => .prim .i64 -- Dependent return type - fall back to i64
354371
355372/-- Build function signature from a Value type. -/
356- def buildSignatureFromType (name : String ) (ty : Value) (arity : Nat) : Signature :=
373+ def buildSignatureFromType (name : Name ) (ty : Value) (arity : Nat) : Signature :=
357374 let (typeParams, paramInfos) := extractParams ty
358375 -- Default type for parameters we can't extract (boxed i64)
359376 let defaultTy : Ty := .prim .i64
@@ -365,7 +382,7 @@ def buildSignatureFromType (name : String) (ty : Value) (arity : Nat) : Signatur
365382 else
366383 { id := ⟨i⟩, name := s! "arg{ i} " , ty := defaultTy : Param }
367384 let retTy := extractReturnType ty
368- { name := name, typeParams := typeParams, params := params, retTy := retTy }
385+ { name := name.display , typeParams := typeParams, params := params, retTy := retTy }
369386
370387/-- Get the Alloy type for a Circuit node entry from its type annotation -/
371388def getNodeType (entry : CNodeEntry) : Ty :=
@@ -550,16 +567,44 @@ partial def lowerNode (graph : CGraph) (nodeId : CNodeId) : StateT NodeState Low
550567 | .app => do
551568 -- Application: call closure with argument
552569 -- aux0 = function, aux1 = argument
553- let fnVal ← match entry.getPort ⟨1 ⟩ with
554- | some fnPort => lowerNode graph fnPort.node
555- | none => StateT.lift (LowerM.emitInst (.copy (.const (.undef closureType))) closureType)
556-
570+ let fnPort := entry.getPort ⟨1 ⟩
571+ let maybeIntrinsicCall ← match fnPort with
572+ | some fp =>
573+ match graph.getNode fp.node with
574+ | some fnEntry =>
575+ match fnEntry.node with
576+ | .ref refId | .alo refId =>
577+ match graph.getDefinition refId with
578+ | some def_ =>
579+ match def_.name.intrinsic? with
580+ | some (Intrinsic.ffiOp op) => pure (some (Sum.inl op : Sum FFIOp String))
581+ | some (Intrinsic.extern name) => pure (some (Sum.inr name : Sum FFIOp String))
582+ | _ => pure none
583+ | none => pure none
584+ | _ => pure none
585+ | none => pure none
586+ | none => pure none
587+
588+ -- Lower the argument(s)
557589 let argVal ← match entry.getPort ⟨2 ⟩ with
558590 | some argPort => lowerNode graph argPort.node
559591 | none => StateT.lift (LowerM.emitInst (.copy (.const .unit)) Ty.unit)
560592
561- -- Use the node's type annotation for the result type
562- StateT.lift (LowerM.emitInst (.callClosure (.local fnVal) #[.local argVal] nodeTy) nodeTy)
593+ match maybeIntrinsicCall with
594+ | some (Sum.inl ffiOp) =>
595+ -- FFI intrinsic: emit callIntrinsic
596+ let intrinsicOp := convertFFIOp ffiOp
597+ StateT.lift (LowerM.emitInst (.callIntrinsic intrinsicOp #[.local argVal] nodeTy) nodeTy)
598+ | some (Sum.inr externName) =>
599+ -- Extern function: emit callExtern
600+ StateT.lift (LowerM.emitInst (.callExtern externName #[.local argVal] nodeTy) nodeTy)
601+ | none =>
602+ -- Regular function call: lower the function and call as closure
603+ let fnVal ← match fnPort with
604+ | some fp => lowerNode graph fp.node
605+ | none => StateT.lift (LowerM.emitInst (.copy (.const (.undef closureType))) closureType)
606+ -- Use the node's type annotation for the result type
607+ StateT.lift (LowerM.emitInst (.callClosure (.local fnVal) #[.local argVal] nodeTy) nodeTy)
563608
564609 | .ctor tag arity => do
565610 -- Check for special closure CTOR (tag 0xFFFFFE, arity 2)
@@ -697,13 +742,33 @@ partial def lowerNode (graph : CGraph) (nodeId : CNodeId) : StateT NodeState Low
697742
698743 | .ref refId => do
699744 -- Global reference: get function from book, type comes from annotation
700- let funcId := FuncId.mk refId
701- StateT.lift (LowerM.emitInst (.copy (.func funcId)) nodeTy)
745+ -- Check if this is an intrinsic/extern
746+ match graph.getDefinition refId with
747+ | some def_ =>
748+ match def_.name.intrinsic? with
749+ | some _ =>
750+ StateT.lift (LowerM.emitInst (.copy (.const (.undef nodeTy))) nodeTy)
751+ | none =>
752+ let funcId := FuncId.mk refId
753+ StateT.lift (LowerM.emitInst (.copy (.func funcId)) nodeTy)
754+ | none =>
755+ let funcId := FuncId.mk refId
756+ StateT.lift (LowerM.emitInst (.copy (.func funcId)) nodeTy)
702757
703758 | .alo refId => do
704759 -- Allocation/instantiation: call the referenced function
705- let funcId := FuncId.mk refId
706- StateT.lift (LowerM.emitInst (.call funcId #[] nodeTy) nodeTy)
760+ -- Check if this is an intrinsic/extern
761+ match graph.getDefinition refId with
762+ | some def_ =>
763+ match def_.name.intrinsic? with
764+ | some _ =>
765+ StateT.lift (LowerM.emitInst (.copy (.const (.undef nodeTy))) nodeTy)
766+ | none =>
767+ let funcId := FuncId.mk refId
768+ StateT.lift (LowerM.emitInst (.call funcId #[] nodeTy) nodeTy)
769+ | none =>
770+ let funcId := FuncId.mk refId
771+ StateT.lift (LowerM.emitInst (.call funcId #[] nodeTy) nodeTy)
707772
708773 | .use => do
709774 -- Strict evaluation: force the term, then continue
@@ -837,12 +902,14 @@ def lowerGraph (graph : CGraph) (moduleName : String := "main") : Module := Id.r
837902 -- Lower each definition in the book
838903 for i in [:graph.book.size] do
839904 if let some def_ := graph.book[i]? then
840- let funcId := FuncId.mk i
841- let func := lowerDefinition graph def_ funcId
842- module := module.addFunc func
905+ -- Skip intrinsic/extern functions
906+ if not def_.name.isIntrinsic then
907+ let funcId := FuncId.mk i
908+ let func := lowerDefinition graph def_ funcId
909+ module := module.addFunc func
843910
844911 -- Set main function if present
845- if let some (idx, _) := graph.findDefinition "main" then
912+ if let some (idx, _) := graph.findDefinitionByDisplay "main" then
846913 module := module.withMain (FuncId.mk idx)
847914
848915 module
0 commit comments