Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 30 additions & 5 deletions modules/dasLLVM/daslib/llvm_exe.das
Original file line number Diff line number Diff line change
Expand Up @@ -454,9 +454,38 @@ def collect_external_functions(standalone_context : LLVMOpaqueValue?; ctx : LLVM

// Creates main function that initializes a standalone JIT context, registers
// all compiled functions, runs init scripts, then calls the program entry point.
def public inject_main(program_context : Context?; ctx : LLVMContextRef; funcs : array<FunctionPtr>;
def public inject_main(program_context : Context?; ctx : LLVMContextRef;
prog : Program?; entry_point : string; mod : LLVMOpaqueModule?;
var types : PrimitiveTypes?, var uids : UidNodes?; strict : bool) : LLVMOpaqueValue? {

let builder = LLVMCreateBuilder()
defer <| ${
LLVMDisposeBuilder(builder)
}
// Collect ALL used functions from the program (not just JIT-compiled ones from `funcs`).
// There shouldn't be any `das` functions in standalone_exe, otherwise it
// will crash.
var funcs : array<FunctionPtr>
var has_no_jit = false
prog |> for_each_module <| $(m) {
if (m.name == "llvm_func" || m.name == "llvm_macro") {
return
}
m |> for_each_function("") <| $(fun) {
if (fun.flags.used) {
if (!fun.flags.builtIn && fun.moreFlags.requestNoJit) {
has_no_jit = true
to_log(LOG_ERROR, "LLVM EXE: function '{fun.name}' is marked no_jit but standalone exe requires all functions to be JIT-compiled\n")
}
funcs |> emplace(fun)
}
}
}
if (strict && has_no_jit) {
to_log(LOG_ERROR, "Cannot build standalone exe: some functions are no_jit in strict mode\n")
return null
}

var start_fn_name = ""
var no_return = true
for (fn in funcs) {
Expand All @@ -483,10 +512,6 @@ def public inject_main(program_context : Context?; ctx : LLVMContextRef; funcs :
)
)
let main_fn = LLVMAddFunctionWithType(mod, "main", main_fn_type)
let builder = LLVMCreateBuilder()
defer <| ${
LLVMDisposeBuilder(builder)
}
let entry = LLVMAppendBasicBlockInContext(ctx, main_fn, "entry")
LLVMPositionBuilderAtEnd(builder, entry)

Expand Down
6 changes: 5 additions & 1 deletion modules/dasLLVM/daslib/llvm_jit.das
Original file line number Diff line number Diff line change
Expand Up @@ -6334,8 +6334,9 @@ def public generate_globals_initialization_fn(ctx : Context?; prog : Program?;
}
visitor.ffunc = globals_fn
let entry = LLVMAppendBasicBlockInContext(g_ctx, globals_fn, "entry")
let body = LLVMAppendBasicBlockInContext(g_ctx, globals_fn, "body")
visitor.function_entry = entry
LLVMPositionBuilderAtEnd(visitor.g_builder, entry)
LLVMPositionBuilderAtEnd(visitor.g_builder, body)
let ctx_param = LLVMGetParam(globals_fn, 0u)
prog |> for_each_module <| $(mod) {
mod |> for_each_global() <| $(glob) {
Expand Down Expand Up @@ -6369,6 +6370,9 @@ def public generate_globals_initialization_fn(ctx : Context?; prog : Program?;
}
}
LLVMBuildRetVoid(visitor.g_builder)
// terminate entry block with branch to body (entry only has allocas from at_function_entry)
LLVMPositionBuilderAtEnd(visitor.g_builder, entry)
LLVMBuildBr(visitor.g_builder, body)
visitor.adapter := null
unsafe {
delete visitor
Expand Down
14 changes: 14 additions & 0 deletions modules/dasLLVM/daslib/llvm_jit_intrin.das
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,19 @@ def public has_intrinsic(expr : smart_ptr<ExprCallFunc>) {
var result = false
assume argType = expr.arguments[0]._type
let call_name = "{expr.func._module.name}::{expr.func.name}"

// We skip some intrinsics below, because g_intrin_lookup
// is not enough and `pfun` can return null sometimes.
// But we don't have full picture without arguments.
// Anyway, assertion in lookup_intrinsic guarantees consistency.
if (call_name == "$::length" && !argType.isGoodArrayType) {
// table<string; json::JsonValue>
// $::dasvector`smart_ptr`Variable&
return false
}
if (!expr.arguments |> empty() && argType.isHandle) {
// intrinsics can't have handle types:
// int64(clock)
return false
}
g_intrin_lookup |> get(call_name) <| $(pfun) {
Expand All @@ -136,6 +148,8 @@ def public lookup_intinsic(g_ctx : LLVMContextRef; g_builder : LLVMOpaqueBuilder
g_intrin_lookup |> get(call_name) <| $(pfun) {
result = pfun |> invoke(JitCtx(ctx = g_ctx, builder = g_builder, types = types), expr, arguments)
}
// Check initrinsic consistency
verify(result != null == has_intrinsic(expr))
return result
}

Expand Down
2 changes: 1 addition & 1 deletion modules/dasLLVM/daslib/llvm_macro.das
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ class JIT_LLVM : AstSimulateMacro {
}
}
if (gen_exe) {
let fn = inject_main(ctx, g_ctx, funcs, prog, exe_main, g_mod, g_prim_t, uids, exe_strict)
let fn = inject_main(ctx, g_ctx, prog, exe_main, g_mod, g_prim_t, uids, exe_strict)
if (fn == null) {
finalize_jit(use_dll, gen_exe, g_dynamic_lib_handle)
// JIT failed. Couldn't create executable.
Expand Down
14 changes: 14 additions & 0 deletions src/builtin/module_jit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
#include "daScript/misc/performance_time.h"
#include "daScript/misc/sysos.h"

#ifdef DAS_ENABLE_DYN_INCLUDES
#include "daScript/ast/dyn_modules.h"
#include "daScript/simulate/fs_file_info.h"
#endif

#include "daScript/ast/ast.h" // astTypeInfo
#include "daScript/ast/ast_handle.h" // addConstant
#include "daScript/ast/ast_interop.h" // addExtern
Expand Down Expand Up @@ -210,11 +215,13 @@ extern "C" {
policies.debugger = false;
context.setup(totalVariables, globalStringHeapSize, policies, {});
context.globalsSize = 32000;
context.sharedOwner = true;
for (int i = 0; i < totalVariables; i++) {
globalVariables[i] = GlobalVariable{};
}
context.allocateGlobalsAndShared();
memset(context.globals, 0, context.globalsSize);
memset(context.shared, 0, context.sharedSize);

// Instead of copying everything like in standalone contexts
// Let's add only things we really need.
Expand Down Expand Up @@ -958,5 +965,12 @@ static void init() {
extern "C" {
DAS_API void jit_initialize_modules () {
init();
#ifdef DAS_ENABLE_DYN_INCLUDES
das::daScriptEnvironment::ensure();
auto access = das::make_smart<das::FsFileAccess>();
das::TextPrinter tout;
das::require_dynamic_modules(access, das::getDasRoot(), "", tout);
#endif
das::Module::Initialize();
}
}
2 changes: 1 addition & 1 deletion utils/mcp/main.das
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def main() {
let sg_check = detect_ast_grep()
if (!empty(sg_check)) {
ast_grep_available = true
log_write("ast-grep detected — grep_usage tool enabled")
log_write("ast-grep detected ({sg_check}) — grep_usage tool enabled")
} else {
log_write("WARNING: ast-grep not found — grep_usage tool disabled")
}
Expand Down
2 changes: 2 additions & 0 deletions utils/mcp/tools/common.das
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ require math public
require strings public
require fio public

var ast_grep_cmd : string

struct ContentItem {
@rename = "type" _type : string
text : string
Expand Down
37 changes: 31 additions & 6 deletions utils/mcp/tools/grep_usage.das
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,45 @@ require common public
require daslib/json
require daslib/json_boost

def detect_ast_grep() : string {
var found = ""
def private try_ast_grep(cmd : string) : bool {
var found = false
unsafe {
popen("sg --version") <| $(f) {
popen("{cmd} --version") <| $(f) {
if (f == null) {
return
}
let line = fgets(f)
if (find(line, "ast-grep") >= 0) {
found = "sg"
found = true
}
}
}
return found
}

def detect_ast_grep() : string {
// try bare "sg" first (works when .venv is activated or sg is on PATH)
if (try_ast_grep("sg")) {
return "sg"
}
// try .venv paths (not activated): Scripts/ on Windows, bin/ on Linux/macOS
let das_root = get_das_root()
for (subdir in ["Scripts", "bin"]) {
let venv_sg = "{das_root}/.venv/{subdir}/sg"
if (try_ast_grep(venv_sg)) {
return venv_sg
}
}
return ""
}

def get_ast_grep_cmd() : string {
if (empty(ast_grep_cmd)) {
ast_grep_cmd = detect_ast_grep()
}
return ast_grep_cmd
}

def json_to_int(v : JsonValue?) : int {
if (v == null) {
return 0
Expand Down Expand Up @@ -60,9 +83,11 @@ def do_grep_usage(symbol, directory, context_lines_str, glob_filter : string) :
let das_root = get_das_root()
let search_dir = resolve_path(!empty(directory) ? directory : ".")
// build ast-grep command
var cmd = "sg run -p \"{symbol}\" -l daslang --json \"{search_dir}\""
let sg = get_ast_grep_cmd()
let cd_root = "cd \"{das_root}\" && "
var cmd = "{cd_root}{sg} run -p \"{symbol}\" -l daslang --json \"{search_dir}\""
if (!empty(glob_filter)) {
cmd = "sg run -p \"{symbol}\" -l daslang --globs \"{glob_filter}\" --json \"{search_dir}\""
cmd = "{cd_root}{sg} run -p \"{symbol}\" -l daslang --globs \"{glob_filter}\" --json \"{search_dir}\""
}
var raw_json : string
unsafe {
Expand Down
9 changes: 6 additions & 3 deletions utils/mcp/tools/outline.das
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ options no_unused_function_arguments = false
options no_unused_block_arguments = false

require common public
require grep_usage public
require daslib/json
require daslib/json_boost
require daslib/strings_boost
Expand Down Expand Up @@ -230,12 +231,14 @@ def do_outline(file, glob_filter : string) : string {
// glob mode: scan directory
target = das_root
}
var cmd = "sg scan -r \"{rules_path}\" --json \"{target}\""
let sg = get_ast_grep_cmd()
let cd_root = "cd \"{das_root}\" && "
var cmd = "{cd_root}{sg} scan -r \"{rules_path}\" --json \"{target}\""
if (!empty(glob_filter) && !empty(file)) {
// both file and glob — use glob as filter
cmd = "sg scan -r \"{rules_path}\" --globs \"{glob_filter}\" --json \"{resolve_path(file)}\""
cmd = "{cd_root}{sg} scan -r \"{rules_path}\" --globs \"{glob_filter}\" --json \"{resolve_path(file)}\""
} elif (!empty(glob_filter)) {
cmd = "sg scan -r \"{rules_path}\" --globs \"{glob_filter}\" --json \"{das_root}\""
cmd = "{cd_root}{sg} scan -r \"{rules_path}\" --globs \"{glob_filter}\" --json \"{das_root}\""
}
var raw_json : string
unsafe {
Expand Down
Loading