mirror of
https://github.com/RoBaertschi/tt.git
synced 2025-04-15 21:43:30 +00:00
amd64: function call support WIP broken
This commit is contained in:
parent
9cfb80e790
commit
8137b45788
@ -101,6 +101,7 @@ const (
|
||||
|
||||
// One operand
|
||||
Idiv Opcode = "idiv"
|
||||
Push Opcode = "push"
|
||||
|
||||
// No operands
|
||||
Ret Opcode = "ret"
|
||||
@ -159,6 +160,12 @@ func (j JmpInstruction) InstructionString() string {
|
||||
return fmt.Sprintf("jmp %s", j)
|
||||
}
|
||||
|
||||
type Call string
|
||||
|
||||
func (c Call) InstructionString() string {
|
||||
return fmt.Sprintf("call %s", c)
|
||||
}
|
||||
|
||||
type SetCCInstruction struct {
|
||||
Cond CondCode
|
||||
Dst Operand
|
||||
@ -168,6 +175,18 @@ func (si *SetCCInstruction) InstructionString() string {
|
||||
return fmt.Sprintf("set%s %s", si.Cond, si.Dst.OperandString(One))
|
||||
}
|
||||
|
||||
type AllocateStack uint
|
||||
|
||||
func (as AllocateStack) InstructionString() string {
|
||||
return fmt.Sprintf("sub rsp, %d", as)
|
||||
}
|
||||
|
||||
type DeallocateStack uint
|
||||
|
||||
func (ds DeallocateStack) InstructionString() string {
|
||||
return fmt.Sprintf("add rsp, %d", ds)
|
||||
}
|
||||
|
||||
type OperandSize int
|
||||
|
||||
type Operand interface {
|
||||
@ -202,6 +221,54 @@ func (r Register) OperandString(size OperandSize) string {
|
||||
return "eax"
|
||||
}
|
||||
return "rax"
|
||||
case CX:
|
||||
switch size {
|
||||
case One:
|
||||
return "cl"
|
||||
case Four:
|
||||
return "ecx"
|
||||
}
|
||||
return "rcx"
|
||||
case DX:
|
||||
switch size {
|
||||
case One:
|
||||
return "dl"
|
||||
case Four:
|
||||
return "edx"
|
||||
}
|
||||
return "rdx"
|
||||
case DI:
|
||||
switch size {
|
||||
case One:
|
||||
return "dil"
|
||||
case Four:
|
||||
return "edi"
|
||||
}
|
||||
return "rdi"
|
||||
case SI:
|
||||
switch size {
|
||||
case One:
|
||||
return "sil"
|
||||
case Four:
|
||||
return "esi"
|
||||
}
|
||||
return "rsi"
|
||||
case R8:
|
||||
switch size {
|
||||
case One:
|
||||
return "r8b"
|
||||
case Four:
|
||||
return "r8d"
|
||||
}
|
||||
return "r8"
|
||||
case R9:
|
||||
switch size {
|
||||
case One:
|
||||
return "r9b"
|
||||
case Four:
|
||||
return "r9d"
|
||||
}
|
||||
return "r9"
|
||||
case R10:
|
||||
switch size {
|
||||
case One:
|
||||
@ -218,8 +285,9 @@ func (r Register) OperandString(size OperandSize) string {
|
||||
return "r11d"
|
||||
}
|
||||
return "r11"
|
||||
default:
|
||||
panic(fmt.Sprintf("unexpected amd64.Register: %#v", r))
|
||||
}
|
||||
return "INVALID_REGISTER"
|
||||
}
|
||||
|
||||
type Imm int64
|
||||
|
@ -2,6 +2,7 @@ package amd64
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"slices"
|
||||
|
||||
"robaertschi.xyz/robaertschi/tt/ast"
|
||||
"robaertschi.xyz/robaertschi/tt/ttir"
|
||||
@ -122,6 +123,67 @@ func cgInstruction(i ttir.Instruction) []Instruction {
|
||||
return []Instruction{JmpInstruction(i)}
|
||||
case *ttir.Copy:
|
||||
return []Instruction{&SimpleInstruction{Opcode: Mov, Lhs: toAsmOperand(i.Dst), Rhs: toAsmOperand(i.Src)}}
|
||||
case *ttir.Call:
|
||||
registerArgs := i.Arguments[0:min(len(callConvArgs), len(i.Arguments))]
|
||||
stackArgs := []ttir.Operand{}
|
||||
if len(callConvArgs) < len(i.Arguments) {
|
||||
stackArgs = i.Arguments[len(callConvArgs):len(i.Arguments)]
|
||||
}
|
||||
|
||||
stackPadding := 0
|
||||
if len(stackArgs)%2 != 0 {
|
||||
stackPadding = 8
|
||||
}
|
||||
|
||||
instructions := []Instruction{}
|
||||
|
||||
if stackPadding > 0 {
|
||||
instructions = append(instructions, AllocateStack(stackPadding))
|
||||
}
|
||||
|
||||
for i, arg := range registerArgs {
|
||||
instructions = append(instructions,
|
||||
&SimpleInstruction{
|
||||
Opcode: Mov,
|
||||
Rhs: toAsmOperand(arg),
|
||||
Lhs: callConvArgs[i],
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
for _, arg := range slices.Backward(stackArgs) {
|
||||
switch arg := toAsmOperand(arg).(type) {
|
||||
case Imm:
|
||||
instructions = append(instructions, &SimpleInstruction{Opcode: Push, Lhs: arg})
|
||||
case Register:
|
||||
instructions = append(instructions, &SimpleInstruction{Opcode: Push, Lhs: arg})
|
||||
case Pseudo:
|
||||
instructions = append(instructions,
|
||||
&SimpleInstruction{Opcode: Mov, Rhs: arg, Lhs: AX},
|
||||
&SimpleInstruction{Opcode: Push, Lhs: AX},
|
||||
)
|
||||
case Stack:
|
||||
instructions = append(instructions,
|
||||
&SimpleInstruction{Opcode: Mov, Rhs: arg, Lhs: AX},
|
||||
&SimpleInstruction{Opcode: Push, Lhs: AX},
|
||||
)
|
||||
default:
|
||||
panic(fmt.Sprintf("unexpected amd64.Operand: %#v", arg))
|
||||
}
|
||||
}
|
||||
|
||||
instructions = append(instructions, Call(i.FunctionName))
|
||||
bytesToRemove := 8*len(stackArgs) + stackPadding
|
||||
if bytesToRemove != 0 {
|
||||
instructions = append(instructions, DeallocateStack(bytesToRemove))
|
||||
}
|
||||
|
||||
if i.ReturnValue != nil {
|
||||
asmDst := toAsmOperand(i.ReturnValue)
|
||||
instructions = append(instructions, &SimpleInstruction{Opcode: Mov, Rhs: AX, Lhs: asmDst})
|
||||
}
|
||||
|
||||
return instructions
|
||||
default:
|
||||
panic(fmt.Sprintf("unexpected ttir.Instruction: %#v", i))
|
||||
}
|
||||
@ -239,11 +301,11 @@ func rpInstruction(i Instruction, r *replacePseudoPass) Instruction {
|
||||
Cond: i.Cond,
|
||||
Dst: pseudoToStack(i.Dst, r),
|
||||
}
|
||||
case *JumpCCInstruction, JmpInstruction, Label:
|
||||
case *JumpCCInstruction, JmpInstruction, Label, AllocateStack, DeallocateStack, Call:
|
||||
return i
|
||||
default:
|
||||
panic(fmt.Sprintf("unexpected amd64.Instruction: %#v", i))
|
||||
}
|
||||
|
||||
panic("invalid instruction")
|
||||
}
|
||||
|
||||
func pseudoToStack(op Operand, r *replacePseudoPass) Operand {
|
||||
@ -347,9 +409,9 @@ func fixupInstruction(i Instruction) []Instruction {
|
||||
case *SetCCInstruction:
|
||||
|
||||
return []Instruction{i}
|
||||
case *JumpCCInstruction, JmpInstruction, Label:
|
||||
case *JumpCCInstruction, JmpInstruction, Label, AllocateStack, DeallocateStack, Call:
|
||||
return []Instruction{i}
|
||||
default:
|
||||
panic(fmt.Sprintf("unexpected amd64.Instruction: %#v", i))
|
||||
}
|
||||
|
||||
panic("invalid instruction")
|
||||
}
|
||||
|
21
design.md
21
design.md
@ -22,3 +22,24 @@ fn main() = {
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## ABI
|
||||
|
||||
ABI Considarations:
|
||||
|
||||
Each file is a module. Everything inside a module is prefixed with the module name. For Example:
|
||||
|
||||
```asm
|
||||
# - In module1 folder
|
||||
# mod module1;
|
||||
# fn test(): i64 = ...
|
||||
module1_test:
|
||||
# - In module1/module2 folder
|
||||
# mod module2;
|
||||
# fn test(): i64 = ...
|
||||
module1_module2_test:
|
||||
```
|
||||
|
||||
Except the main module, all members of the main module are exposed with their concrete name.
|
||||
|
||||
If we ever add something like generics, that will have to be encoded in the function name too.
|
||||
|
Loading…
x
Reference in New Issue
Block a user