Skip to content

Commit

Permalink
Asm syntax pragma (#23119)
Browse files Browse the repository at this point in the history
(Inspired by this pragma in nir asm PR)

`inlineAsmSyntax` pragma allowing specify target inline assembler syntax
in `asm` stmt.

It prevents compiling code with different of the target CC inline asm
syntax, i.e. it will not allow gcc inline asm code to be compiled with
vcc.

```nim
proc nothing() =
  asm {.inlineAsmSyntax: "gcc".} """
    nop
  """
```

The current C(C++) backend implementation cannot generate code for gcc
and for vcc at the same time. For example, `{.inlineAsmSyntax: "vcc".}`
with the ICC compiler will not generate code with intel asm syntax, even
though ICC can use both gcc-like asm and vcc-like. For implement support
for gcc and for vcc at the same time in ICC compiler, we need to
refactor extccomp

---------

Co-authored-by: Andreas Rumpf <[email protected]>
  • Loading branch information
ASVIEST and Araq authored Dec 25, 2023
1 parent 6f3d3fd commit 1324d2e
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 15 deletions.
15 changes: 15 additions & 0 deletions compiler/ccgstmts.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1537,6 +1537,21 @@ proc genAsmStmt(p: BProc, t: PNode) =
assert(t.kind == nkAsmStmt)
genLineDir(p, t)
var s = newRopeAppender()

var asmSyntax = ""
if (let p = t[0]; p.kind == nkPragma):
for i in p:
if whichPragma(i) == wAsmSyntax:
asmSyntax = i[1].strVal

if asmSyntax != "" and
not (
asmSyntax == "gcc" and hasGnuAsm in CC[p.config.cCompiler].props or
asmSyntax == "vcc" and hasGnuAsm notin CC[p.config.cCompiler].props):
localError(
p.config, t.info,
"Your compiler does not support the specified inline assembler")

genAsmOrEmitStmt(p, t, isAsmStmt=true, s)
# see bug #2362, "top level asm statements" seem to be a mis-feature
# but even if we don't do this, the example in #2362 cannot possibly
Expand Down
32 changes: 18 additions & 14 deletions compiler/pragmas.nim
Original file line number Diff line number Diff line change
Expand Up @@ -153,20 +153,6 @@ proc pragmaEnsures(c: PContext, n: PNode) =
n[1] = c.semExpr(c, n[1])
closeScope(c)

proc pragmaAsm*(c: PContext, n: PNode): char =
result = '\0'
if n != nil:
for i in 0..<n.len:
let it = n[i]
if it.kind in nkPragmaCallKinds and it.len == 2 and it[0].kind == nkIdent:
case whichKeyword(it[0].ident)
of wSubsChar:
if it[1].kind == nkCharLit: result = chr(int(it[1].intVal))
else: invalidPragma(c, it)
else: invalidPragma(c, it)
else:
invalidPragma(c, it)

proc setExternName(c: PContext; s: PSym, extname: string, info: TLineInfo) =
# special cases to improve performance:
if extname == "$1":
Expand Down Expand Up @@ -307,6 +293,24 @@ proc pragmaNoForward*(c: PContext, n: PNode; flag=sfNoForward) =
"use {.experimental: \"codeReordering\".} instead; " &
(if flag == sfNoForward: "{.noForward.}" else: "{.reorder.}") & " is deprecated")

proc pragmaAsm*(c: PContext, n: PNode): char =
## Checks asm pragmas and get's the asm subschar (default: '`').
result = '\0'
if n != nil:
for i in 0..<n.len:
let it = n[i]
if it.kind in nkPragmaCallKinds and it.len == 2 and it[0].kind == nkIdent:
case whichKeyword(it[0].ident)
of wSubsChar:
if it[1].kind == nkCharLit: result = chr(int(it[1].intVal))
else: invalidPragma(c, it)
of wAsmSyntax:
let s = expectStrLit(c, it)
if s notin ["gcc", "vcc"]: invalidPragma(c, it)
else: invalidPragma(c, it)
else:
invalidPragma(c, it)

proc processCallConv(c: PContext, n: PNode) =
if n.kind in nkPragmaCallKinds and n.len == 2 and n[1].kind == nkIdent:
let sw = whichKeyword(n[1].ident)
Expand Down
2 changes: 1 addition & 1 deletion compiler/wordrecg.nim
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ type
wComputedGoto = "computedGoto", wExperimental = "experimental", wDoctype = "doctype",
wWrite = "write", wGensym = "gensym", wInject = "inject", wDirty = "dirty",
wInheritable = "inheritable", wThreadVar = "threadvar", wEmit = "emit",
wAsmNoStackFrame = "asmNoStackFrame", wImplicitStatic = "implicitStatic",
wAsmNoStackFrame = "asmNoStackFrame", wAsmSyntax = "asmSyntax", wImplicitStatic = "implicitStatic",
wGlobal = "global", wCodegenDecl = "codegenDecl", wUnchecked = "unchecked",
wGuard = "guard", wLocks = "locks", wPartial = "partial", wExplain = "explain",
wLiftLocals = "liftlocals", wEnforceNoRaises = "enforceNoRaises", wSystemRaisesDefect = "systemRaisesDefect",
Expand Down
17 changes: 17 additions & 0 deletions doc/manual_experimental.md
Original file line number Diff line number Diff line change
Expand Up @@ -2595,3 +2595,20 @@ method foo(x: Base) {.base.} = discard
```
It gives an error: method `foo` can be defined only in the same module with its type (Base).
asmSyntax pragma
================
The `asmSyntax` pragma is used to specify target inline assembler syntax in an `asm` statement.
It prevents compiling code with different of the target CC inline asm syntax, i.e. it will not allow gcc inline asm code to be compiled with vcc.
```nim
proc nothing() =
asm {.asmSyntax: "gcc".}"""
nop
"""
```
The current C(C++) backend implementation cannot generate code for gcc and for vcc at the same time. For example, `{.asmSyntax: "vcc".}` with the ICC compiler will not generate code with intel asm syntax, even though ICC can use both gcc-like and vcc-like asm.

0 comments on commit 1324d2e

Please sign in to comment.