From 95fbaf73d3479143891af5888d775b154ad4f842 Mon Sep 17 00:00:00 2001 From: araq Date: Tue, 24 Sep 2024 22:33:01 +0200 Subject: [PATCH] progress --- src/nifc/amd64/asm_grammar.nif | 5 ++ src/nifc/amd64/asm_grammar.nim | 87 +++++++++++++++----- src/nifc/amd64/asm_model.nim | 22 ++++-- src/nifc/amd64/genasm.nim | 7 +- src/nifc/amd64/genasm_e.nim | 140 +++++++++++++++++++++++++++++---- src/nifc/amd64/machine.nim | 23 +++--- 6 files changed, 232 insertions(+), 52 deletions(-) diff --git a/src/nifc/amd64/asm_grammar.nif b/src/nifc/amd64/asm_grammar.nif index 563e007..f55ce00 100644 --- a/src/nifc/amd64/asm_grammar.nif +++ b/src/nifc/amd64/asm_grammar.nif @@ -124,12 +124,17 @@ (jz Label) (jnz Label) (jg Label) + (jng Label) (jge Label) + (jnge Label) (ja Label) + (jna Label) (jae Label) + (jnae Label) (nop) (ret) (syscall) + (lab "" SYMBOLDEF) (comment "; " (OR IDENT SYMBOL STRINGLITERAL)) ) (DO "nl")) ) diff --git a/src/nifc/amd64/asm_grammar.nim b/src/nifc/amd64/asm_grammar.nim index 7f57ab3..181d235 100644 --- a/src/nifc/amd64/asm_grammar.nim +++ b/src/nifc/amd64/asm_grammar.nim @@ -1254,8 +1254,8 @@ proc genInstruction(c: var Context): bool = or2 = true break or3 var kw66 = false - if isTag(c, JgeT): - emitTag(c, "jge") + if isTag(c, JngT): + emitTag(c, "jng") if not genLabel(c): error(c, "Label expected") break or3 @@ -1264,8 +1264,8 @@ proc genInstruction(c: var Context): bool = or2 = true break or3 var kw67 = false - if isTag(c, JaT): - emitTag(c, "ja") + if isTag(c, JgeT): + emitTag(c, "jge") if not genLabel(c): error(c, "Label expected") break or3 @@ -1274,8 +1274,8 @@ proc genInstruction(c: var Context): bool = or2 = true break or3 var kw68 = false - if isTag(c, JaeT): - emitTag(c, "jae") + if isTag(c, JngeT): + emitTag(c, "jnge") if not genLabel(c): error(c, "Label expected") break or3 @@ -1283,6 +1283,46 @@ proc genInstruction(c: var Context): bool = if kw68: or2 = true break or3 + var kw69 = false + if isTag(c, JaT): + emitTag(c, "ja") + if not genLabel(c): + error(c, "Label expected") + break or3 + kw69 = matchParRi(c) + if kw69: + or2 = true + break or3 + var kw70 = false + if isTag(c, JnaT): + emitTag(c, "jna") + if not genLabel(c): + error(c, "Label expected") + break or3 + kw70 = matchParRi(c) + if kw70: + or2 = true + break or3 + var kw71 = false + if isTag(c, JaeT): + emitTag(c, "jae") + if not genLabel(c): + error(c, "Label expected") + break or3 + kw71 = matchParRi(c) + if kw71: + or2 = true + break or3 + var kw72 = false + if isTag(c, JnaeT): + emitTag(c, "jnae") + if not genLabel(c): + error(c, "Label expected") + break or3 + kw72 = matchParRi(c) + if kw72: + or2 = true + break or3 if matchAndEmitTag(c, NopT, "nop"): or2 = true break or3 @@ -1292,25 +1332,36 @@ proc genInstruction(c: var Context): bool = if matchAndEmitTag(c, SyscallT, "syscall"): or2 = true break or3 - var kw69 = false + var kw73 = false + if isTag(c, LabT): + emit(c, "") + var sym74 = declareSym(c) + if not success(sym74): + error(c, "SYMBOLDEF expected") + break or3 + kw73 = matchParRi(c) + if kw73: + or2 = true + break or3 + var kw75 = false if isTag(c, CommentT): emit(c, "; ") - var or70 = false - block or71: + var or76 = false + block or77: if matchIdent(c): - or70 = true - break or71 + or76 = true + break or77 if lookupSym(c): - or70 = true - break or71 + or76 = true + break or77 if matchStringLit(c): - or70 = true - break or71 - if not or70: + or76 = true + break or77 + if not or76: error(c, "invalid Instruction") break or3 - kw69 = matchParRi(c) - if kw69: + kw75 = matchParRi(c) + if kw75: or2 = true break or3 if not or2: return false diff --git a/src/nifc/amd64/asm_model.nim b/src/nifc/amd64/asm_model.nim index 29b5d01..46e2219 100644 --- a/src/nifc/amd64/asm_model.nim +++ b/src/nifc/amd64/asm_model.nim @@ -114,13 +114,17 @@ const JzT* = TagId(111) JnzT* = TagId(112) JgT* = TagId(113) - JgeT* = TagId(114) - JaT* = TagId(115) - JaeT* = TagId(116) - NopT* = TagId(117) - RetT* = TagId(118) - SyscallT* = TagId(119) - CommentT* = TagId(120) + JngT* = TagId(114) + JgeT* = TagId(115) + JngeT* = TagId(116) + JaT* = TagId(117) + JnaT* = TagId(118) + JaeT* = TagId(119) + JnaeT* = TagId(120) + NopT* = TagId(121) + RetT* = TagId(122) + SyscallT* = TagId(123) + CommentT* = TagId(124) proc registerTags*() = registerTag "global", GlobalT @@ -234,9 +238,13 @@ proc registerTags*() = registerTag "jz", JzT registerTag "jnz", JnzT registerTag "jg", JgT + registerTag "jng", JngT registerTag "jge", JgeT + registerTag "jnge", JngeT registerTag "ja", JaT + registerTag "jna", JnaT registerTag "jae", JaeT + registerTag "jnae", JnaeT registerTag "nop", NopT registerTag "ret", RetT registerTag "syscall", SyscallT diff --git a/src/nifc/amd64/genasm.nim b/src/nifc/amd64/genasm.nim index e00c78a..b9213b8 100644 --- a/src/nifc/amd64/genasm.nim +++ b/src/nifc/amd64/genasm.nim @@ -120,9 +120,6 @@ proc getTempVar(c: var GeneratedCode): TempVar = result = TempVar(c.temps) inc c.temps -proc defineLabel(c: var GeneratedCode; lab: Label; info: PackedLineInfo) = - c.code.addSymDef "L." & $int(lab), info - proc useLabel(c: var GeneratedCode; lab: Label; info: PackedLineInfo) = c.addSym "L." & $int(lab), info @@ -140,6 +137,10 @@ template buildTreeI(c: var GeneratedCode; keyw: TagId; info: PackedLineInfo; bod c.code.buildTree keyw, info: body +proc defineLabel(c: var GeneratedCode; lab: Label; info: PackedLineInfo) = + c.code.buildTree LabT, info: + c.code.addSymDef "L." & $int(lab), info + # Type graph include ".." / preasm / genpreasm_t diff --git a/src/nifc/amd64/genasm_e.nim b/src/nifc/amd64/genasm_e.nim index b73ea91..589e6c5 100644 --- a/src/nifc/amd64/genasm_e.nim +++ b/src/nifc/amd64/genasm_e.nim @@ -9,6 +9,36 @@ # included from genpreasm.nim +proc opposite(t: TagId): TagId = + case t + of JeT: JneT + of JneT: JeT + of JzT: JnzT + of JnzT: JzT + of JgT: JngT + of JgeT: JngeT + of JngeT: JgeT + of JaT: JnaT + of JnaT: JaT + of JaeT: JnaeT + of JnaeT: JaeT + else: NopT + +proc jumpToPutInstr(t: TagId): TagId = + case t + of JeT: SetneT + of JneT: SeteT + of JzT: SetnzT + of JnzT: SetzT + of JgT: SetngT + of JgeT: SetngeT + of JngeT: SetgeT + of JaT: SetnaT + of JnaT: SetaT + of JaeT: SetnaeT + of JnaeT: SetaeT + else: NopT + proc emitLoc*(c: var GeneratedCode; loc: Location) = case loc.kind of Undef: @@ -132,6 +162,10 @@ proc genAsgn(c: var GeneratedCode; dest, src: Location) = c.buildTree MovapdT: c.emitLoc dest c.emitLoc src + elif src.kind == InFlag: + assert dest.kind != InFlag + c.buildTree jumpToPutInstr(src.flag): + c.emitLoc dest elif dest.typ.size < 0'i32 or dest.typ.size > 8'i32: assert dest.typ.size > 0'i32, "size not set!" assert false, "implement rep byte copy loop" @@ -149,6 +183,8 @@ proc genAsgn(c: var GeneratedCode; dest, src: Location) = proc into(c: var GeneratedCode; dest: var Location; src: Location) = if dest.kind == Undef: dest = src + elif dest.kind == InFlag and src.kind == InFlag and dest.flag == NopT: + dest.flag = src.flag else: genAsgn c, dest, src @@ -306,6 +342,52 @@ proc genAddr(c: var GeneratedCode; t: Tree; n: NodePos; dest: var Location) = else: error c.m, "expected expression but got: ", t, n +proc genLoad(c: var GeneratedCode; dest: var Location; address: Location) = + if dest.kind == Undef: + dest = scratchReg(c.rega) + # XXX Floating point? What if it doesn't even fit a register? + + let opc = if address.typ.kind == AFloat: MovapdT else: MovT + c.buildTree opc: + emitLoc c, dest + c.buildTree Mem1T: + emitLoc c, address + +proc genLvalue(c: var GeneratedCode; t: Tree; n: NodePos; dest: var Location) = + let info = t[n].info + case t[n].kind + of Sym: + let lit = t[n].litId + let def = c.m.defs.getOrDefault(lit) + case def.kind + of ProcC: + let d = Location(typ: AddrTyp, kind: InData, data: lit) + into c, dest, d + of VarC, ParamC: + let d = c.locals[lit] + if d.kind in {InStack}: + genLoad c, dest, d + else: + into c, dest, d + of GvarC, ConstC: + let typ = c.globals[lit] + let d = Location(flags: {Indirect}, typ: typ, kind: InData, data: lit) + genLoad c, dest, d + of TvarC: + let typ = c.globals[lit] + let d = Location(flags: {Indirect}, typ: typ, kind: InTls, data: lit) + genLoad c, dest, d + of EfldC: + assert false, "enum fields not implemented" + else: + error c.m, "undeclared identifier: ", t, n + of DerefC, AtC, PatC, DotC: + var d = Location(kind: Undef) + genAddr c, t, n, d + genLoad c, dest, d + else: + error c.m, "expected expression but got: ", t, n + proc genStrLit(c: var GeneratedCode; s: string; info: PackedLineInfo; dest: var Location) = var id = c.strings.getOrDefault(s, -1) var symId: string @@ -394,6 +476,36 @@ proc genFjmp(c: var GeneratedCode; t: Tree; n: NodePos; jmpTarget: Label; opc = c.useLabel jmpTarget, info ]# +type + CondJmpKind = enum + Fjmp # jump if the condition is false (the `and` operator) + Tjmp # jump if the condition is true (the `or` operator) + +proc genCond(c: var GeneratedCode; t: Tree; n: NodePos; dest: var Location; jk: CondJmpKind) = + let l1 = getLabel(c) + let (a, b) = sons2(t, n) + # tell the pipeline we need the result in a flag: + var destA = Location(kind: InFlag, flag: NopT) + genx(c, t, a, destA) + assert destA.kind == InFlag + let opc = if jk == Tjmp: destA.flag else: opposite(destA.flag) + c.buildTree opc: + c.useLabel l1, t[n].info + genx(c, t, b, dest) + c.defineLabel l1, t[n].info + +proc genCmp(c: var GeneratedCode; t: Tree; n: NodePos; dest: var Location; opc: TagId) = + var d = Location(kind: InFlag, flag: opc) + let (a, b) = sons2(t, n) + let x = gen(c, t, a) + let y = gen(c, t, b) + c.buildTree CmpT: + emitLoc c, x + emitLoc c, y + c.freeTemp y + c.freeTemp x + c.into dest, d + proc genDataVal(c: var GeneratedCode; t: Tree; n: NodePos) = let d = gen(c, t, n) emitLoc c, d @@ -521,18 +633,18 @@ proc genx(c: var GeneratedCode; t: Tree; n: NodePos; dest: var Location) = of BitorC: typedBinOp OrT of BitxorC: typedBinOp XorT of BitnotC: typedUnOp NotT - of AndC: genCond c, t, n, FjmpT - of OrC: genCond c, t, n, TjmpT - of NotC: unOp NotT - of NegC: unOp NegT - of EqC: cmpOp EqT - of LeC: cmpOp LeT - of LtC: cmpOp LtT - of CastC, ConvC: - assert mode == WantValue - genConv c, t, n - of SufC: - let (value, suffix) = sons2(t, n) - genx(c, t, value, mode) + of NegC: typedUnOp NegT + of AndC: genCond c, t, n, dest, Fjmp + of OrC: genCond c, t, n, dest, Tjmp + of EqC: genCmp c, t, n, dest, JneT + of LeC: genCmp c, t, n, dest, JgT + of LtC: genCmp c, t, n, dest, JgeT + + #of NotC: unOp NotT + #of CastC, ConvC: + # genConv c, t, n + #of SufC: + # let (value, suffix) = sons2(t, n) + # genx(c, t, value, mode) else: - genLvalue c, t, n, mode, dest + genLvalue c, t, n, dest diff --git a/src/nifc/amd64/machine.nim b/src/nifc/amd64/machine.nim index 24936ec..90d8dbe 100644 --- a/src/nifc/amd64/machine.nim +++ b/src/nifc/amd64/machine.nim @@ -10,6 +10,8 @@ import ".." / nifc_model import ".." / native / slots +import nifstreams except StrId + type IntReg* = distinct byte FloatReg* = distinct byte @@ -95,15 +97,16 @@ proc regName*(r: FloatReg): string = result.addInt int(r) const - CarryFlag = CpuFlag(0) - ParityFlag = CpuFlag(2) - AuxFlag = CpuFlag(4) - ZeroFlag = CpuFlag(6) - SignFlag = CpuFlag(7) - TrapFlag = CpuFlag(8) - InterruptFlag = CpuFlag(9) - DirFlag = CpuFlag(10) - OverflowFlag = CpuFlag(11) + CarryFlag* = CpuFlag(0) + ParityFlag* = CpuFlag(2) + AuxFlag* = CpuFlag(4) + ZeroFlag* = CpuFlag(6) + SignFlag* = CpuFlag(7) + TrapFlag* = CpuFlag(8) + InterruptFlag* = CpuFlag(9) + DirFlag* = CpuFlag(10) + OverflowFlag* = CpuFlag(11) + UndefinedFlag* = CpuFlag(255) # Other flags not modelled as we don't need them. proc flagName*(f: CpuFlag): string = @@ -186,7 +189,7 @@ type reg1*, reg2*: IntReg of InRegFp: regf*: FloatReg of InStack: slot*: int - of InFlag: flag*: CpuFlag + of InFlag: flag*: TagId of JumpMode: label*: int of InData, InTls: data*: StrId