-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
NIR: asm statement support, Wip #22992
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
ddaea3b
73eb391
73f9b60
a4ddb3b
03af260
545d35a
5cefc65
cd5de29
c0ab580
78a4c61
e4af3f0
e9221ae
8419151
57802ed
a1f9c3f
f41557d
fc8b91f
68bc65d
3d4f45e
119e15b
24b6c55
bb463f1
5f58ec9
330ae88
21ee838
cc45710
1b88194
c7d3093
11a6fe8
ec8beea
540ef8f
5d6c354
f0efd4c
811e6ab
94c7fa0
747ead5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -14,6 +14,7 @@ from std / strutils import toOctal | |||||
import .. / ic / [bitabs, rodfiles] | ||||||
import nirtypes, nirinsts, nirfiles | ||||||
import ../../dist/checksums/src/checksums/md5 | ||||||
import target_props | ||||||
|
||||||
type | ||||||
Token = LitId # indexing into the tokens BiTable[string] | ||||||
|
@@ -31,6 +32,7 @@ type | |||||
Semicolon = ";" | ||||||
Comma = ", " | ||||||
Space = " " | ||||||
Quote = $'"' | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
Colon = ": " | ||||||
Dot = "." | ||||||
Arrow = "->" | ||||||
|
@@ -63,6 +65,7 @@ proc fillTokenTable(tab: var BiTable[string]) = | |||||
type | ||||||
GeneratedCode* = object | ||||||
m: NirModule | ||||||
props: TargetProps | ||||||
includes: seq[LitId] | ||||||
includedHeaders: IntSet | ||||||
data: seq[LitId] | ||||||
|
@@ -75,8 +78,11 @@ type | |||||
generatedTypes: IntSet | ||||||
mangledModules: Table[LitId, LitId] | ||||||
|
||||||
proc initGeneratedCode*(m: sink NirModule): GeneratedCode = | ||||||
result = GeneratedCode(m: m, code: @[], tokens: initBiTable[string]()) | ||||||
proc initGeneratedCode*(m: sink NirModule; props: sink TargetProps): GeneratedCode = | ||||||
result = GeneratedCode( | ||||||
m: m, code: @[], tokens: initBiTable[string](), | ||||||
props: props | ||||||
) | ||||||
fillTokenTable(result.tokens) | ||||||
|
||||||
proc add*(g: var GeneratedCode; t: PredefinedToken) {.inline.} = | ||||||
|
@@ -444,7 +450,9 @@ proc genProcDecl(c: var GeneratedCode; t: Tree; n: NodePos; isExtern: bool) = | |||||
let lit = t[y].litId | ||||||
raiseAssert "cannot eval: " & c.m.lit.strings[lit] | ||||||
else: discard | ||||||
of PragmaId: discard | ||||||
of PragmaId: | ||||||
let key = cast[PragmaKey](t[prc].rawOperand) | ||||||
if key == AsmNoStackFrame: c.add "NIM_NAKED " | ||||||
else: break | ||||||
next t, prc | ||||||
|
||||||
|
@@ -554,6 +562,54 @@ template moveToDataSection(body: untyped) = | |||||
c.data.add c.code[i] | ||||||
setLen c.code, oldLen | ||||||
|
||||||
proc genGccAsm(c: var GeneratedCode; t: Tree; n: NodePos) = | ||||||
c.add "__asm__ " | ||||||
c.add ParLe | ||||||
c.add NewLine | ||||||
|
||||||
var asmTemplate = true | ||||||
var left = 0 | ||||||
var s = "" | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is |
||||||
|
||||||
template maybeAddQuote = | ||||||
if asmTemplate: c.add Quote | ||||||
|
||||||
template findSecUpdate(s: string): bool = | ||||||
var result = false | ||||||
for i in s: | ||||||
if i == ':': result = true | ||||||
if i notin {' ', '\t', '\n'}: break #found char | ||||||
result | ||||||
|
||||||
maybeAddQuote | ||||||
for ch in sons(t, n): | ||||||
if t[ch].kind == Verbatim: | ||||||
s = c.m.lit.strings[t[ch].litId] | ||||||
left = 0 | ||||||
for i in 0..s.high: | ||||||
if s[i] == '\n': | ||||||
c.add s[left..i - 1] | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What? Why? Didn't you write a parser for the asm? Shouldn't it split it at newlines if they are important? |
||||||
if asmTemplate: c.add r"\n" | ||||||
maybeAddQuote | ||||||
left = i + 1 | ||||||
c.add NewLine | ||||||
if not findSecUpdate(s[i+1..^1]): maybeAddQuote # next '"' | ||||||
elif s[i] == ':': asmTemplate = false | ||||||
else: | ||||||
c.add s[left..^1] | ||||||
c.gen(t, ch) | ||||||
if not findSecUpdate(s): | ||||||
c.add s[left..^1] | ||||||
maybeAddQuote | ||||||
c.add ParRi | ||||||
c.add Semicolon | ||||||
|
||||||
proc genVisualCPPAsm(c: var GeneratedCode; t: Tree; n: NodePos) = | ||||||
c.add "__asm " | ||||||
c.add CurlyLe | ||||||
c.gen(t, n) # inline asm | ||||||
c.add CurlyRi | ||||||
|
||||||
proc gen(c: var GeneratedCode; t: Tree; n: NodePos) = | ||||||
case t[n].kind | ||||||
of Nop: | ||||||
|
@@ -807,11 +863,65 @@ proc gen(c: var GeneratedCode; t: Tree; n: NodePos) = | |||||
of NumberConv: genNumberConv c, t, n | ||||||
of CheckedObjConv: binaryop "" | ||||||
of ObjConv: binaryop "" | ||||||
of Emit: raiseAssert "cannot interpret: Emit" | ||||||
of ProcDecl: genProcDecl c, t, n, false | ||||||
of ForeignProcDecl: genProcDecl c, t, n, true | ||||||
of PragmaPair, PragmaId, TestOf, Yld, SetExc, TestExc: | ||||||
c.add "cannot interpret: " & $t[n].kind | ||||||
of Verbatim: | ||||||
c.add c.m.lit.strings[t[n].litId] | ||||||
of Emit: | ||||||
requireInfo t, n, IsGlobal | ||||||
let | ||||||
target = cast[EmitTargetKind](t[n.firstSon].rawOperand) | ||||||
code = lastSon(t, n) | ||||||
|
||||||
case target: | ||||||
of Asm: | ||||||
requireInfo t, n, InPure | ||||||
|
||||||
# Resolve asm overloads (as example for icc inlineAsmSyntax pragma must be specified) | ||||||
var inlineAsmSyntax = c.props.inlineAsmSyntax | ||||||
if haveInfo(t, n, InlineAsmSyntax): | ||||||
inlineAsmSyntax = inlineAsmSyntax * { | ||||||
fetchInfo(t, n, InlineAsmSyntax).infoVal( | ||||||
t, InlineAsmSyntaxKind | ||||||
) | ||||||
} | ||||||
|
||||||
if inlineAsmSyntax.len > 1: | ||||||
raiseAssert "Ambiguous asm syntax, please specify via inlineAsmSyntax pragma" | ||||||
|
||||||
let isBasicAsm = ( | ||||||
fetchInfo(t, n, IsGlobal).infoVal(t, bool) or | ||||||
fetchInfo(t, n, InPure).infoVal(t, bool) | ||||||
) and inlineAsmSyntax != {VisualCPP} | ||||||
|
||||||
if inlineAsmSyntax.len == 0 and not isBasicAsm: | ||||||
raiseAssert "Your compiler does not support the specified inline assembler" | ||||||
|
||||||
if not isBasicAsm: | ||||||
if inlineAsmSyntax == {GCCExtendedAsm}: genGccAsm(c, t, code) | ||||||
elif inlineAsmSyntax == {VisualCPP}: genVisualCPPAsm(c, t, code) | ||||||
else: raiseAssert "Not implemented inline asm syntax" | ||||||
else: | ||||||
assert ( | ||||||
isLastSon(t, code, code.firstSon) and | ||||||
t[code.firstSon].kind == Verbatim | ||||||
), "Invalid basic asm. Basic asm should be only one verbatim" | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't the frontend do this? |
||||||
genGccAsm(c, t, code) | ||||||
|
||||||
of Code: | ||||||
raiseAssert"not supported" | ||||||
|
||||||
of EmitTarget: | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is a EmitTarget an opcode of its own? We have a pragma annotation system in place for this... |
||||||
discard | ||||||
|
||||||
of EmitCode: | ||||||
for ch in sons(t, n): | ||||||
gen c, t, ch | ||||||
|
||||||
of Info, InfoId: | ||||||
discard "Info can't generate code" | ||||||
|
||||||
const | ||||||
Prelude = """ | ||||||
|
@@ -940,6 +1050,11 @@ typedef NU8 NU; | |||||
#define nimCheckRange(x, a, b, L) ({if (x < a || x > b) goto L; x}) | ||||||
#define nimCheckIndex(x, a, L) ({if (x >= a) goto L; x}) | ||||||
|
||||||
#ifdef _MSC_VER | ||||||
#define NIM_NAKED __declspec(naked) | ||||||
#else | ||||||
#define NIM_NAKED __attribute__((naked)) | ||||||
#endif | ||||||
""" | ||||||
|
||||||
proc traverseCode(c: var GeneratedCode) = | ||||||
|
@@ -958,8 +1073,8 @@ proc traverseCode(c: var GeneratedCode) = | |||||
c.init.add c.code[i] | ||||||
setLen c.code, oldLen | ||||||
|
||||||
proc generateCode*(inp, outp: string) = | ||||||
var c = initGeneratedCode(load(inp)) | ||||||
proc generateCode*(inp, outp: string; props: sink TargetProps) = | ||||||
var c = initGeneratedCode(load(inp), props) | ||||||
|
||||||
var co = TypeOrder() | ||||||
traverseTypes(c.m.types, c.m.lit, co) | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's not how the rest of the codebase indents the
case
statement.