parallel assembly
This commit is contained in:
113
build.cm
113
build.cm
@@ -467,6 +467,64 @@ Build.build_static = function(packages, target, output, buildtype) {
|
||||
// Native .cm compilation (source → mcode → QBE IL → .o → .dylib)
|
||||
// ============================================================================
|
||||
|
||||
// Batched native compilation: split functions into batches, run QBE on each,
|
||||
// assemble in parallel, return array of .o paths.
|
||||
// il_parts: {data: text, functions: [text, ...]}
|
||||
// cc: C compiler path
|
||||
// tmp_prefix: prefix for temp files (e.g. /tmp/cell_native_<hash>)
|
||||
function compile_native_batched(il_parts, cc, tmp_prefix) {
|
||||
var nfuncs = length(il_parts.functions)
|
||||
var nbatch = 8
|
||||
var o_paths = []
|
||||
var s_paths = []
|
||||
var asm_cmds = []
|
||||
var batch_fns = null
|
||||
var batch_il = null
|
||||
var asm_text = null
|
||||
var s_path = null
|
||||
var o_path = null
|
||||
var end = 0
|
||||
var bi = 0
|
||||
var fi = 0
|
||||
var ai = 0
|
||||
var rc = null
|
||||
var parallel_cmd = null
|
||||
|
||||
if (nfuncs < nbatch) nbatch = nfuncs
|
||||
if (nbatch < 1) nbatch = 1
|
||||
|
||||
// Generate .s files: run QBE on each batch
|
||||
while (bi < nbatch) {
|
||||
batch_fns = []
|
||||
end = nfuncs * (bi + 1) / nbatch
|
||||
while (fi < end) {
|
||||
batch_fns[] = il_parts.functions[fi]
|
||||
fi = fi + 1
|
||||
}
|
||||
batch_il = il_parts.data + "\n\n" + text(batch_fns, "\n")
|
||||
asm_text = os.qbe(batch_il)
|
||||
s_path = tmp_prefix + '_b' + text(bi) + '.s'
|
||||
o_path = tmp_prefix + '_b' + text(bi) + '.o'
|
||||
fd.slurpwrite(s_path, stone(blob(asm_text)))
|
||||
s_paths[] = s_path
|
||||
o_paths[] = o_path
|
||||
bi = bi + 1
|
||||
}
|
||||
|
||||
// Assemble all batches in parallel
|
||||
while (ai < length(s_paths)) {
|
||||
asm_cmds[] = cc + ' -c ' + s_paths[ai] + ' -o ' + o_paths[ai]
|
||||
ai = ai + 1
|
||||
}
|
||||
parallel_cmd = text(asm_cmds, ' & ') + ' & wait'
|
||||
rc = os.system(parallel_cmd)
|
||||
if (rc != 0) {
|
||||
print('Parallel assembly failed'); disrupt
|
||||
}
|
||||
|
||||
return o_paths
|
||||
}
|
||||
|
||||
// Post-process QBE IL: insert dead labels after ret/jmp (QBE requirement)
|
||||
function qbe_insert_dead_labels(il_text) {
|
||||
var lines = array(il_text, "\n")
|
||||
@@ -536,10 +594,8 @@ Build.compile_native = function(src_path, target, buildtype, pkg) {
|
||||
if (pkg) {
|
||||
sym_name = shop.c_symbol_for_file(pkg, fd.basename(src_path))
|
||||
}
|
||||
var il = qbe_emit(optimized, qbe_macros, sym_name)
|
||||
|
||||
// Step 3: Post-process (insert dead labels)
|
||||
il = qbe_insert_dead_labels(il)
|
||||
var il_parts = qbe_emit(optimized, qbe_macros, sym_name)
|
||||
var il = il_parts.data + "\n\n" + text(il_parts.functions, "\n")
|
||||
|
||||
// Content hash for cache key
|
||||
var hash = content_hash(src + '\n' + _target + '\nnative')
|
||||
@@ -550,22 +606,14 @@ Build.compile_native = function(src_path, target, buildtype, pkg) {
|
||||
if (fd.is_file(dylib_path))
|
||||
return dylib_path
|
||||
|
||||
// Step 4: QBE compile IR to assembly (in-process)
|
||||
// Compile and assemble via batched parallel pipeline
|
||||
var tmp = '/tmp/cell_native_' + hash
|
||||
var s_path = tmp + '.s'
|
||||
var o_path = tmp + '.o'
|
||||
var rt_o_path = '/tmp/cell_qbe_rt.o'
|
||||
|
||||
var asm_text = os.qbe(il)
|
||||
fd.slurpwrite(s_path, stone(blob(asm_text)))
|
||||
var o_paths = compile_native_batched(il_parts, cc, tmp)
|
||||
|
||||
// Step 5: Assemble
|
||||
var rc = os.system(cc + ' -c ' + s_path + ' -o ' + o_path)
|
||||
if (rc != 0) {
|
||||
print('Assembly failed for: ' + src_path); disrupt
|
||||
}
|
||||
|
||||
// Step 7: Compile QBE runtime stubs if needed
|
||||
// Compile QBE runtime stubs if needed
|
||||
var rc = null
|
||||
if (!fd.is_file(rt_o_path)) {
|
||||
qbe_rt_path = shop.get_package_dir('core') + '/qbe_rt.c'
|
||||
rc = os.system(cc + ' -c ' + qbe_rt_path + ' -o ' + rt_o_path + ' -fPIC')
|
||||
@@ -574,14 +622,19 @@ Build.compile_native = function(src_path, target, buildtype, pkg) {
|
||||
}
|
||||
}
|
||||
|
||||
// Step 8: Link dylib
|
||||
// Link dylib
|
||||
var link_cmd = cc + ' -shared -fPIC'
|
||||
if (tc.system == 'darwin') {
|
||||
link_cmd = link_cmd + ' -undefined dynamic_lookup'
|
||||
} else if (tc.system == 'linux') {
|
||||
link_cmd = link_cmd + ' -Wl,--allow-shlib-undefined'
|
||||
}
|
||||
link_cmd = link_cmd + ' ' + o_path + ' ' + rt_o_path + ' -o ' + dylib_path
|
||||
var oi = 0
|
||||
while (oi < length(o_paths)) {
|
||||
link_cmd = link_cmd + ' ' + o_paths[oi]
|
||||
oi = oi + 1
|
||||
}
|
||||
link_cmd = link_cmd + ' ' + rt_o_path + ' -o ' + dylib_path
|
||||
|
||||
rc = os.system(link_cmd)
|
||||
if (rc != 0) {
|
||||
@@ -625,8 +678,7 @@ Build.compile_native_ir = function(optimized, src_path, opts) {
|
||||
if (pkg) {
|
||||
sym_name = shop.c_symbol_for_file(pkg, fd.basename(src_path))
|
||||
}
|
||||
var il = qbe_emit(optimized, qbe_macros, sym_name)
|
||||
il = qbe_insert_dead_labels(il)
|
||||
var il_parts = qbe_emit(optimized, qbe_macros, sym_name)
|
||||
|
||||
var src = text(fd.slurp(src_path))
|
||||
var hash = content_hash(src + '\n' + _target + '\nnative')
|
||||
@@ -637,19 +689,14 @@ Build.compile_native_ir = function(optimized, src_path, opts) {
|
||||
if (fd.is_file(dylib_path))
|
||||
return dylib_path
|
||||
|
||||
// Compile and assemble via batched parallel pipeline
|
||||
var tmp = '/tmp/cell_native_' + hash
|
||||
var s_path = tmp + '.s'
|
||||
var o_path = tmp + '.o'
|
||||
var rt_o_path = '/tmp/cell_qbe_rt.o'
|
||||
|
||||
var asm_text = os.qbe(il)
|
||||
fd.slurpwrite(s_path, stone(blob(asm_text)))
|
||||
|
||||
var rc = os.system(cc + ' -c ' + s_path + ' -o ' + o_path)
|
||||
if (rc != 0) {
|
||||
print('Assembly failed for: ' + src_path); disrupt
|
||||
}
|
||||
var o_paths = compile_native_batched(il_parts, cc, tmp)
|
||||
|
||||
// Compile QBE runtime stubs if needed
|
||||
var rc = null
|
||||
if (!fd.is_file(rt_o_path)) {
|
||||
qbe_rt_path = shop.get_package_dir('core') + '/qbe_rt.c'
|
||||
rc = os.system(cc + ' -c ' + qbe_rt_path + ' -o ' + rt_o_path + ' -fPIC')
|
||||
@@ -658,13 +705,19 @@ Build.compile_native_ir = function(optimized, src_path, opts) {
|
||||
}
|
||||
}
|
||||
|
||||
// Link dylib
|
||||
var link_cmd = cc + ' -shared -fPIC'
|
||||
if (tc.system == 'darwin') {
|
||||
link_cmd = link_cmd + ' -undefined dynamic_lookup'
|
||||
} else if (tc.system == 'linux') {
|
||||
link_cmd = link_cmd + ' -Wl,--allow-shlib-undefined'
|
||||
}
|
||||
link_cmd = link_cmd + ' ' + o_path + ' ' + rt_o_path + ' -o ' + dylib_path
|
||||
var oi = 0
|
||||
while (oi < length(o_paths)) {
|
||||
link_cmd = link_cmd + ' ' + o_paths[oi]
|
||||
oi = oi + 1
|
||||
}
|
||||
link_cmd = link_cmd + ' ' + rt_o_path + ' -o ' + dylib_path
|
||||
|
||||
rc = os.system(link_cmd)
|
||||
if (rc != 0) {
|
||||
|
||||
Reference in New Issue
Block a user