-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #42 from kntkymt/fix/generater-structure
Genとアセンブリ出力を分離する
- Loading branch information
Showing
8 changed files
with
1,057 additions
and
489 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
private extension AsmRepresent.Instruction.Address { | ||
var description: String { | ||
switch self { | ||
case .register(let register): register.rawValue | ||
case .distance(let register, let diff): "\(register.rawValue), #\(diff)" | ||
} | ||
} | ||
} | ||
|
||
public enum ArmAsmPrinter { | ||
public static func print(instructions: [AsmRepresent.Instruction]) -> String { | ||
instructions.map { print(instruction: $0) }.reduce("") { $0 + $1 } | ||
} | ||
|
||
static func print(instruction: AsmRepresent.Instruction) -> String { | ||
/// opecode a, b | ||
func inst(_ opecode: String, _ a: AsmRepresent.Register, _ b: AsmRepresent.Register) -> String { | ||
" \(opecode) \(a.rawValue), \(b.rawValue)\n" | ||
} | ||
|
||
/// opecode a, #immediate | ||
func inst(_ opecode: String, _ a: AsmRepresent.Register, _ immediate: Int64) -> String { | ||
" \(opecode) \(a.rawValue), #\(immediate)\n" | ||
} | ||
|
||
/// opecode a, b, c | ||
func inst(_ opecode: String, _ a: AsmRepresent.Register, _ b: AsmRepresent.Register, _ c: AsmRepresent.Register) -> String { | ||
" \(opecode) \(a.rawValue), \(b.rawValue), \(c.rawValue)\n" | ||
} | ||
|
||
/// opecode a, b, #immediate | ||
func inst(_ opecode: String, _ a: AsmRepresent.Register, _ b: AsmRepresent.Register, _ immediate: Int64) -> String { | ||
" \(opecode) \(a.rawValue), \(b.rawValue), #\(immediate)\n" | ||
} | ||
|
||
/// opecode a, [address] | ||
func inst(_ opecode: String, _ a: AsmRepresent.Register, _ address: AsmRepresent.Instruction.Address) -> String { | ||
" \(opecode) \(a.rawValue), [\(address.description)]\n" | ||
} | ||
|
||
/// opecode a, b, [address] | ||
func inst(_ opecode: String, _ a: AsmRepresent.Register, _ b: AsmRepresent.Register, _ address: AsmRepresent.Instruction.Address) -> String { | ||
" \(opecode) \(a.rawValue), \(b.rawValue), [\(address.description)]\n" | ||
} | ||
|
||
/// opecode label | ||
func inst(_ opecode: String, _ label: String) -> String { | ||
" \(opecode) \(fixLabel(label))\n" | ||
} | ||
|
||
/// AppleClangではmainが_main じゃないとダメなので対応 | ||
func fixLabel(_ label: String) -> String { | ||
label == "main" ? "_main" : label | ||
} | ||
|
||
return switch instruction { | ||
case .mov(let dst, let src): | ||
inst("mov", dst, src) | ||
case .movi(let dst, let immediate): | ||
inst("mov", dst, immediate) | ||
case .add(let dst, let src1, let src2): | ||
inst("add", dst, src1, src2) | ||
case .addi(let dst, let src, let immediate): | ||
inst("add", dst, src, immediate) | ||
case .sub(let dst, let src1, let src2): | ||
inst("sub", dst, src1, src2) | ||
case .subi(let dst, let src, let immediate): | ||
inst("sub", dst, src, immediate) | ||
case .mul(let dst, let src1, let src2): | ||
inst("mul", dst, src1, src2) | ||
case .muli(let dst, let src, let immediate): | ||
inst("mul", dst, src, immediate) | ||
case .div(let dst, let src1, let src2): | ||
inst("sdiv", dst, src1, src2) | ||
case .divi(let dst, let src, let immediate): | ||
inst("sdiv", dst, src, immediate) | ||
case .push(let src): | ||
inst("sub", .sp, .sp, 16) | ||
+ inst("str", src, .register(.sp)) | ||
case .pop(let dst): | ||
inst("ldr", dst, .register(.sp)) | ||
+ inst("add", .sp, .sp, 16) | ||
case .addr(let dst, let label): | ||
" adrp \(dst.rawValue), \(label)@GOTPAGE\n" | ||
+ " ldr \(dst.rawValue), [\(dst.rawValue), \(label)@GOTPAGEOFF]\n" | ||
case .str(let src, let address): | ||
inst("str", src, address) | ||
case .strb(let src, let address): | ||
inst("strb", src, address) | ||
case .stp(let src1, let src2, let address): | ||
inst("stp", src1, src2, address) | ||
case .ldr(let dst, let address): | ||
inst("ldr", dst, address) | ||
case .ldrb(let dst, let address): | ||
inst("ldrb", dst, address) | ||
case .ldp(let dst1, let dst2, let address): | ||
inst("ldp", dst1, dst2, address) | ||
case .cmp(let src1, let src2): | ||
inst("cmp", src1, src2) | ||
case .cmpi(let src, let immediate): | ||
inst("cmp", src, immediate) | ||
case .cset(let dst, let flag): | ||
" cset \(dst.rawValue), \(flag.rawValue)\n" | ||
case .beq(let label): | ||
inst("beq", label) | ||
case .b(let label): | ||
inst("b", label) | ||
case .bl(let label): | ||
inst("bl", label) | ||
case .neg(let dst, let src): | ||
inst("neg", dst, src) | ||
case .lsli(let dst, let src, let immediate): | ||
inst("lsl", dst, src, Int64(immediate)) | ||
case .ret: | ||
" ret\n" | ||
case .label(let label): | ||
"\(fixLabel(label)):\n" | ||
case .p2align(let factor): | ||
".p2align \(factor)\n" | ||
case .section(let kinds): | ||
".section \(kinds.map { $0.rawValue }.joined(separator: ","))\n" | ||
case .globl(let label): | ||
".globl \(fixLabel(label))\n" | ||
case .dataDecl(let kind, let value): | ||
" .\(kind.rawValue) \(value)\n" | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
|
||
public enum AsmRepresent { | ||
|
||
public enum Instruction { | ||
case mov(dst: Register, src: Register) | ||
case movi(dst: Register, immediate: Int64) | ||
|
||
case add(dst: Register, src1: Register, src2: Register) | ||
case addi(dst: Register, src: Register, immediate: Int64) | ||
case sub(dst: Register, src1: Register, src2: Register) | ||
case subi(dst: Register, src: Register, immediate: Int64) | ||
case mul(dst: Register, src1: Register, src2: Register) | ||
case muli(dst: Register, src: Register, immediate: Int64) | ||
case div(dst: Register, src1: Register, src2: Register) | ||
case divi(dst: Register, src: Register, immediate: Int64) | ||
|
||
case push(src: Register) | ||
case pop(dst: Register) | ||
|
||
/// dstにlabelのアドレスを入れる | ||
case addr(dst: Register, label: String) | ||
|
||
case str(src: Register, address: Address) | ||
case strb(src: Register, address: Address) | ||
case stp(src1: Register, src2: Register, address: Address) | ||
case ldr(dst: Register, address: Address) | ||
case ldrb(dst: Register, address: Address) | ||
case ldp(dst1: Register, dst2: Register, address: Address) | ||
|
||
case cmp(src1: Register, src2: Register) | ||
case cmpi(src: Register, immediate: Int64) | ||
|
||
case cset(dst: Register, flag: CsetFlag) | ||
|
||
case beq(label: String) | ||
case b(label: String) | ||
case bl(label: String) | ||
|
||
case neg(des: Register, src: Register) | ||
|
||
case lsli(dst: Register, src: Register, immediate: UInt64) | ||
|
||
case ret | ||
|
||
// 実際には命令ではない、別のデータ構造で表すべき? | ||
case label(label: String) | ||
case p2align(factor: UInt64) | ||
case section(kinds: [SectionKind]) | ||
case globl(label: String) | ||
case dataDecl(kind: DataKind, value: String) | ||
|
||
public enum Address { | ||
case register(_ register: Register) | ||
case distance(_ register: Register, _ diff: Int64) | ||
} | ||
|
||
public enum CsetFlag: String { | ||
case eq | ||
case ne | ||
case lt | ||
case le | ||
case gt | ||
case ge | ||
} | ||
|
||
public enum SectionKind: String { | ||
case DATA = "__DATA" | ||
case data = "__data" | ||
case TEXT = "__TEXT" | ||
case cstring = "__cstring" | ||
case cstring_literals = "cstring_literals" | ||
} | ||
|
||
public enum DataKind: String { | ||
case byte | ||
case quad | ||
case asciz | ||
case comm | ||
} | ||
} | ||
|
||
public enum Register: String { | ||
case x0 | ||
case x1 | ||
case x2 | ||
case x3 | ||
case x4 | ||
|
||
case w0 | ||
case w1 | ||
case w2 | ||
case w3 | ||
case w4 | ||
|
||
case x29 | ||
case x30 | ||
|
||
case sp | ||
|
||
static func x(_ index: Int) -> Register { | ||
switch index { | ||
case 0: .x0 | ||
case 1: .x1 | ||
case 2: .x2 | ||
case 3: .x3 | ||
case 4: .x4 | ||
default: fatalError() | ||
} | ||
} | ||
|
||
static func w(_ index: Int) -> Register { | ||
switch index { | ||
case 0: .w0 | ||
case 1: .w1 | ||
case 2: .w2 | ||
case 3: .w3 | ||
case 4: .w4 | ||
default: fatalError() | ||
} | ||
} | ||
} | ||
|
||
} |
Oops, something went wrong.