Skip to content

Commit 7e11a70

Browse files
committed
fix: intrinsics/externs
1 parent 42aab04 commit 7e11a70

File tree

21 files changed

+610
-64
lines changed

21 files changed

+610
-64
lines changed

base.ll

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
; ModuleID = 'base'
2+
declare ptr @malloc(i64 %size)
3+
4+
declare void @free(ptr %ptr)
5+
6+
declare void @soma_era_free(ptr %ptr)
7+
8+
declare void @soma_panic(i32 %msg, i32 %line) noreturn
9+
10+
declare void @llvm.memcpy.p0.p0.i64(ptr %dst, ptr %src, i64 %len, i1 %isvolatile)
11+
12+
declare void @llvm.memset.p0.i64(ptr %dst, i8 %val, i64 %len, i1 %isvolatile)
13+
14+
define i32 @"$base/src/core$$test"() nounwind {
15+
bb0:
16+
%0 = add i32 5, 0
17+
ret i32 %0
18+
}
19+
20+
define i32 @"$base/src/core$$main"() nounwind {
21+
bb0:
22+
%0 = call i32 @"$base/src/core$$main"()
23+
ret i32 %0
24+
}

base/app.ll

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
; ModuleID = 'app'
2+
declare ptr @malloc(i64 %size)
3+
4+
declare void @free(ptr %ptr)
5+
6+
declare void @soma_era_free(ptr %ptr)
7+
8+
declare void @soma_panic(i32 %msg, i32 %line) noreturn
9+
10+
declare void @llvm.memcpy.p0.p0.i64(ptr %dst, ptr %src, i64 %len, i1 %isvolatile)
11+
12+
declare void @llvm.memset.p0.i64(ptr %dst, i8 %val, i64 %len, i1 %isvolatile)
13+
14+
define i32 @"$app/src/core$$test"() nounwind {
15+
bb0:
16+
%0 = add i32 5, 0
17+
ret i32 %0
18+
}
19+
20+
define i32 @soma_main() nounwind {
21+
bb0:
22+
%0 = call i32 @"$app/src/core$$test"()
23+
ret i32 %0
24+
}

base/src/core.soma

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ def strcat :: String -> String -> String
33
@[intrinsic]
44
def int_to_string :: Int -> String
55

6+
def test :: Int = 5
7+
8+
def main :: Int = test
9+
610
data Option a
711
| Some
812
value :: a

base_exe.ll

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
; ModuleID = 'base'
2+
declare ptr @malloc(i64 %size)
3+
4+
declare void @free(ptr %ptr)
5+
6+
declare void @soma_era_free(ptr %ptr)
7+
8+
declare void @soma_panic(i32 %msg, i32 %line) noreturn
9+
10+
declare void @llvm.memcpy.p0.p0.i64(ptr %dst, ptr %src, i64 %len, i1 %isvolatile)
11+
12+
declare void @llvm.memset.p0.i64(ptr %dst, i8 %val, i64 %len, i1 %isvolatile)
13+
14+
define i32 @"$base/src/core$$test"() nounwind {
15+
bb0:
16+
%0 = add i32 5, 0
17+
ret i32 %0
18+
}
19+
20+
define i32 @"$base/src/core$$main"() nounwind {
21+
bb0:
22+
%0 = call i32 @"$base/src/core$$main"()
23+
ret i32 %0
24+
}

compiler/Exe/Somac/Alloy/Block.lean

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,8 @@ where
142142
| .erase val _ => #[val].filterMap extractOperandLocal
143143
| .panic _ _ => #[]
144144
| .intrinsic _ args _ => args.filterMap extractOperandLocal
145+
| .callIntrinsic _ args _ => args.filterMap extractOperandLocal
146+
| .callExtern _ args _ => args.filterMap extractOperandLocal
145147

146148
extractTermLocals : Terminator → Array LocalId
147149
| .jump _ => #[]

compiler/Exe/Somac/Alloy/Func.lean

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -321,13 +321,11 @@ namespace Module
321321
/-- Create an empty module -/
322322
def empty (name : String) : Module := { name }
323323

324-
/-- Add a function -/
324+
/-- Add a function, preserving its existing ID -/
325325
def addFunc (m : Module) (f : Func) : Module :=
326-
let id := FuncId.mk m.funcs.size
327-
let f' := { f with id }
328326
{ m with
329-
funcs := m.funcs.push f'
330-
funcIndex := m.funcIndex.insert f.sig.name id
327+
funcs := m.funcs.push f
328+
funcIndex := m.funcIndex.insert f.sig.name f.id
331329
}
332330

333331
/-- Add a global -/

compiler/Exe/Somac/Alloy/Inst.lean

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,13 @@ inductive Inst where
125125
/-- Panic with message (aborts execution) -/
126126
| panic (msgIdx : Nat) (line : Nat)
127127

128-
/-- Runtime intrinsic call -/
129-
| intrinsic (name : String) (args : Array Operand) (retTy : Ty)
128+
/-- FFI intrinsic operation (compiles to inline LLVM instructions)
129+
These are @[intrinsic] functions like ptr_read, ptr_write, etc. -/
130+
| callIntrinsic (op : IntrinsicOp) (args : Array Operand) (retTy : Ty)
131+
132+
/-- External function call (compiles to LLVM external linkage call)
133+
These are @[extern] functions like malloc, free, etc. -/
134+
| callExtern (name : String) (args : Array Operand) (retTy : Ty)
130135

131136
deriving Repr, Inhabited, Serialize, Deserialize
132137

@@ -140,6 +145,7 @@ def hasResult : Inst → Bool
140145
| .memset _ _ _ => false
141146
| .erase _ _ => false
142147
| .panic _ _ => false
148+
| .callIntrinsic op _ _ => op.hasResult
143149
| _ => true
144150

145151
/-- Get the result type of an instruction (if it has one) -/
@@ -187,6 +193,8 @@ def resultTy : Inst → Option Ty
187193
| .erase _ _ => none
188194
| .panic _ _ => none
189195
| .intrinsic _ _ retTy => some retTy
196+
| .callIntrinsic op _ retTy => if op.hasResult then some retTy else none
197+
| .callExtern _ _ retTy => some retTy
190198

191199
instance : ToString Inst where
192200
toString inst :=
@@ -247,6 +255,12 @@ instance : ToString Inst where
247255
| .intrinsic name args _ =>
248256
let as := String.intercalate ", " (args.toList.map ToString.toString)
249257
s!"intrinsic {name}({as})"
258+
| .callIntrinsic op args _ =>
259+
let as := String.intercalate ", " (args.toList.map ToString.toString)
260+
s!"call.intrinsic {op}({as})"
261+
| .callExtern name args _ =>
262+
let as := String.intercalate ", " (args.toList.map ToString.toString)
263+
s!"call.extern {name}({as})"
250264

251265
end Inst
252266

compiler/Exe/Somac/Alloy/Lower.lean

Lines changed: 84 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import Somac.Alloy.Func
1818
import Somac.Circuit.Graph
1919
import Somac.Circuit.Node
2020
import Soma.Core.Value
21+
import Soma.Core.Name
2122
import Soma.Core.Primitive
2223
import Std.Data.HashMap
2324
import Std.Data.HashSet
@@ -36,6 +37,7 @@ abbrev CLabel := Somac.Circuit.Node.Label
3637
abbrev CNodeEntry := Somac.Circuit.Graph.NodeEntry
3738

3839
open 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 -/
4143
abbrev 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+
213230
open 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 -/
371388
def 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 ⟨1with
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 ⟨2with
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

compiler/Exe/Somac/Alloy/Merge.lean

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@ def remapInst (remap : IdRemap) (moduleName : String) (inst : Inst) : Inst :=
104104
| .free ptr => .free (remapOp ptr)
105105
| .alloca _ => inst
106106
| .panic _ _ => inst
107+
| .callIntrinsic op args retTy => .callIntrinsic op (remapOps args) retTy
108+
| .callExtern name args retTy => .callExtern name (remapOps args) retTy
107109

108110
/-- Rewrite FuncId references in a terminator -/
109111
def remapTerminator (remap : IdRemap) (moduleName : String) (term : Terminator) : Terminator :=
@@ -247,6 +249,7 @@ def registerModule (moduleName : String) (module : Module) (state : MergeState)
247249
def remapModule (moduleName : String) (state : MergeState) : MergeState := Id.run do
248250
let mut result := state.result
249251

252+
-- qualifiedName in addFunc is s!"${moduleName}$${func.sig.name}"
250253
let modulePrefix := s!"${moduleName}$$"
251254

252255
-- Rewrite all functions that belong to this module

compiler/Exe/Somac/Alloy/Monomorphize.lean

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,8 @@ def substInstTypes (inst : Inst) (args : Array Ty) : Inst :=
161161
| .erase val ty => .erase val (subst ty)
162162
| .panic msgIdx line => .panic msgIdx line
163163
| .intrinsic name intrArgs retTy => .intrinsic name intrArgs (subst retTy)
164+
| .callIntrinsic op intrArgs retTy => .callIntrinsic op intrArgs (subst retTy)
165+
| .callExtern name extArgs retTy => .callExtern name extArgs (subst retTy)
164166

165167
/-- Substitute type arguments into a statement -/
166168
def substStmtTypes (stmt : Stmt) (args : Array Ty) : Stmt :=

0 commit comments

Comments
 (0)