ref: 3355f31cb1efe35fab21e39e27c5cadcda93d51d
dir: /mbld/syssel.myr/
use std
use bio
use "opts"
use "types"
pkg bld =
type syssel(@a) = struct
file : byte[:]
line : int
targ : byte[:]
_match : std.htab(byte[:], (int, int))#
_best : std.htab(byte[:], @a)#
;;
generic mksyssel : (b : build#, f : byte[:], line : int, targ : byte[:] -> syssel(@a)#)
generic sysseladd : (b : build#, syssel : syssel(byte[:])#, file : byte[:] -> void)
generic sysseladdlist : (b : build#, syssel : syssel(@a)#, base : byte[:], attrs : byte[:][:], val : @a -> void)
generic sysselfin : (b : build#, syssel : syssel(@a)# -> @a[:])
const addsysattrs : (sa : build#, tags : byte[:][:] -> void)
;;
generic mksyssel = {b, file, line, targ
var syssel
syssel = std.mk([
.file = file,
.line = line,
.targ = targ,
._match = std.mkht(),
._best = std.mkht(),
])
-> syssel
}
generic sysseladd = {b, syssel, f
var basename, attrs
var attrlist
match std.strfind(f, "+")
| `std.Some i:
basename = f[:i]
match std.strrfind(f[i+1:], ".")
| `std.Some j: attrs = f[i+1:][:j]
| `std.None: std.fatal("unrecognized type for file {}\n", f)
;;
| `std.None:
match std.strrfind(f, ".")
| `std.None: std.fatal("unrecognized type for file {}\n", f)
| `std.Some i:
basename = f[:i]
attrs = ""
;;
;;
attrlist = std.strsplit(attrs, "-")
sysseladdlist(b, syssel, basename, attrlist, f)
std.slfree(attrlist)
}
generic sysseladdlist = {b, syssel, base, attrs, val
var nmatch, vscore, s
nmatch = 0
vscore = 0
for a : attrs
s = tagscore(b, a)
if s < 0
nmatch = -1
break
;;
vscore += s
nmatch++
;;
match std.htgetv(syssel._match, base, (-1, -1))
| (curbest, curscore):
if curbest < nmatch || (nmatch >= 0 && curbest == nmatch && curscore < vscore)
std.htput(syssel._match, base, (nmatch, vscore))
std.htput(syssel._best, base, val)
;;
;;
}
const tagscore = {b, tag
var n, v
match std.strfind(tag, ":")
| `std.Some i:
n = tag[:i]
v = parseversion(tag[i+1:])
| `std.None:
n = tag
v = (-1, -1, -1)
;;
match std.htget(b.tags, n)
| `std.None: -> -1
| `std.Some cv: -> versionscore(cv, v)
;;
}
const versionscore = {have, want
var s
s = 0
match (have, want)
| ((a0, a1, a2), (v0, v1, v2)):
if a0 == -1 && a1 == -1 && a2 == -1
-> s
elif v0 == -1 && v1 == -1 && v2 == -1
-> s
else
s = 1_000_000 * (a0 - v0)
if s == 0
s += 1_000 * (a1 - v1)
;;
if s == 0
s += (a2 - v2)
;;
if s >= 0
s = 100_000_000 - s
;;
-> s
;;
;;
}
generic sysselfin = {b, syssel
var keys, nmatch, ret
keys = std.htkeys(syssel._match)
ret = [][:]
for k : keys
(nmatch, _) = std.htgetv(syssel._match, k, (-1, -1))
if nmatch == -1
std.fatal("{}:{}: target {}, no applicable file for '{}'\n", \
syssel.file, syssel.line, syssel.targ, k)
;;
std.slpush(&ret, std.get(std.htget(syssel._best, k)))
;;
std.htfree(syssel._match)
std.htfree(syssel._best)
-> ret
}
const addsysattrs = {b, tags
if opt_alltags.len > 0
for t : opt_alltags
tag(b, t)
;;
else
std.htput(b.tags, opt_sys, opt_sysvers)
match opt_sys
| "freebsd": tag(b, "posixy")
| "netbsd": tag(b, "posixy")
| "openbsd": tag(b, "posixy")
| "osx": tag(b, "posixy")
| "linux": tag(b, "posixy")
| "plan9":
| unknown: std.fatal("unknown system \"{}\"\n", unknown)
;;
match opt_arch
| "x64":
tag(b, "x64")
if supports(CpuidSSE2)
tag(b, "sse2")
;;
if supports(CpuidSSE4)
tag(b, "sse4")
;;
if supports(CpuidFMA)
tag(b, "fma")
;;
| unknown:
std.fatal("unknown architecture {}\n", unknown)
;;
for t : tags
tag(b, t)
;;
loadtagfile(b, "bld.tags")
;;
}
const supports = {feat
match (opt_sys, opt_cpufeatures & feat)
/* The version of gas that's shipped with openbsd is too old. */
| ("openbsd", CpuidSSE4): -> false
| ("openbsd", CpuidFMA): -> false
| ("freebsd", CpuidSSE4): -> false
| ("freebsd", CpuidFMA): -> false
| ("netbsd", CpuidSSE4): -> false
| ("netbsd", CpuidFMA): -> false
| (_, f): -> f == feat
;;
}
const loadtagfile = {b, tagfile
var deptags, tagmap, changed
var tf, lnum
if !std.fexists(tagfile)
-> void
;;
match bio.open(tagfile, bio.Rd)
| `std.Ok f: tf = f
| `std.Err e: std.fatal("could not open tagfile: {}\n", e)
;;
lnum = 0
tagmap = std.mkht()
/*
* Parse the list of tags. Each line is in the form of
*
* tag list ":" tag list
*
* The left hand side of the tag list describes the tags
* that get added if the tags on the right hand side all
* are present.
*/
for ln : bio.byline(tf)
lnum++
match std.strfind(ln, ":")
| `std.None:
for t : std.bytok(ln)
tag(b, t)
;;
continue
| `std.Some idx:
if std.strstrip(ln[:idx]).len == 0
std.fatal("{}:{}: missing tags before ':'\n", tagfile, lnum)
;;
deptags = [][:]
for d : std.bytok(ln[idx+1:])
std.slpush(&deptags, std.sldup(d))
;;
for t : std.bytok(ln[:idx])
match std.htget(tagmap, t)
| `std.Some v:
std.slpush(&v, deptags)
std.htput(tagmap, t, v)
| `std.None:
std.htput(tagmap, std.sldup(t), std.sldup([deptags][:]))
;;
;;
;;
;;
bio.close(tf)
/*
* Because tags may depend on other tags, we need to iterate
* here until the set of tags reach a fixed point. Each tag
* that we insert may potentially free other tags to be inserted,
* so either we make progress on the finite set of tags, or we
* don't make a change and break out of the loop.
*/
changed = true
while changed
changed = false
for (k, vss) : std.byhtkeyvals(tagmap)
if std.hthas(b.tags, k)
continue
;;
for vs : vss
for v : vs
if tagscore(b, v) == -1
goto next
;;
;;
tag(b, k)
changed = true
:next
;;
;;
;;
for (k, vss) : std.byhtkeyvals(tagmap)
std.slfree(k)
for vs : vss
for v : vs
std.slfree(v)
;;
std.slfree(vs)
;;
std.slfree(vss)
;;
}
const tag = {b, t
var v
match std.strfind(t, ":")
| `std.None:
std.htput(b.tags, std.sldup(t), (-1, -1, -1))
| `std.Some idx:
v = parseversion(t[idx+1:])
std.htput(b.tags, std.sldup(t[:idx]), v)
;;
}