diff --git a/asm/inst.go b/asm/inst.go index 71d60d88..58b7abc2 100644 --- a/asm/inst.go +++ b/asm/inst.go @@ -135,6 +135,8 @@ func (fgen *funcGen) newValueInst(ident ir.LocalIdent, old ast.ValueInstruction) return fgen.newPhiInst(ident, old) case *ast.SelectInst: return fgen.newSelectInst(ident, old) + case *ast.FreezeInst: + return fgen.newFreezeInst(ident, old) case *ast.CallInst: return fgen.newCallInst(ident, old) case *ast.VAArgInst: @@ -290,6 +292,8 @@ func (fgen *funcGen) irValueInst(new ir.Instruction, old ast.ValueInstruction) e return fgen.irPhiInst(new, old) case *ast.SelectInst: return fgen.irSelectInst(new, old) + case *ast.FreezeInst: + return fgen.irFreezeInst(new, old) case *ast.CallInst: return fgen.irCallInst(new, old) case *ast.VAArgInst: diff --git a/asm/inst_other.go b/asm/inst_other.go index 049f480c..bf057f6c 100644 --- a/asm/inst_other.go +++ b/asm/inst_other.go @@ -71,6 +71,16 @@ func (fgen *funcGen) newSelectInst(ident ir.LocalIdent, old *ast.SelectInst) (*i return &ir.InstSelect{LocalIdent: ident, Typ: typ}, nil } +// newFreezeInst returns a new IR freeze instruction (without body but with +// type) based on the given AST freeze instruction. +func (fgen *funcGen) newFreezeInst(ident ir.LocalIdent, old *ast.FreezeInst) (*ir.InstFreeze, error) { + typ, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + return &ir.InstFreeze{LocalIdent: ident, Typ: typ}, nil +} + // newCallInst returns a new IR call instruction (without body but with type) // based on the given AST call instruction. func (fgen *funcGen) newCallInst(ident ir.LocalIdent, old *ast.CallInst) (*ir.InstCall, error) { @@ -249,6 +259,23 @@ func (fgen *funcGen) irSelectInst(new ir.Instruction, old *ast.SelectInst) error return nil } +// --- [ freeze ] ---------------------------------------------------------- + +// irFreezeInst translates the given AST freeze instruction into an +// equivalent IR instruction. +func (fgen *funcGen) irFreezeInst(new ir.Instruction, old *ast.FreezeInst) error { + inst, ok := new.(*ir.InstFreeze) + if !ok { + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstFreeze, got %T", new)) + } + x, err := fgen.irTypeValue(old.X()) + if err != nil { + return errors.WithStack(err) + } + inst.X = x + return nil +} + // --- [ call ] ---------------------------------------------------------------- // irCallInst translates the given AST call instruction into an equivalent IR diff --git a/go.mod b/go.mod index b565c9bc..eca10622 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.13 require ( github.com/google/go-cmp v0.3.1 github.com/kr/pretty v0.1.0 - github.com/llir/ll v0.0.0-20200410135743-26a2120d00af + github.com/llir/ll v0.0.0-20200414154635-a942fd56e775 github.com/mewmew/float v0.0.0-20191226120903-16bbe2fdd85e github.com/pkg/errors v0.8.1 golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4 diff --git a/go.sum b/go.sum index 1485b157..04f450e9 100644 --- a/go.sum +++ b/go.sum @@ -11,6 +11,8 @@ github.com/llir/ll v0.0.0-20200407120059-f42e46f6afef h1:KrExuElmSZGZzTBa0ek+h33 github.com/llir/ll v0.0.0-20200407120059-f42e46f6afef/go.mod h1:8W5HJz80PitAyPZUpOcljQxTu6LD5YKW1URTo+OjVoc= github.com/llir/ll v0.0.0-20200410135743-26a2120d00af h1:REN5MVxGjO0ztKmH9N1LXNFkP/kSewZIbLxZ45QPGeg= github.com/llir/ll v0.0.0-20200410135743-26a2120d00af/go.mod h1:8W5HJz80PitAyPZUpOcljQxTu6LD5YKW1URTo+OjVoc= +github.com/llir/ll v0.0.0-20200414154635-a942fd56e775 h1:htltNQ09aljaA4owdZv203tQ2Gz6PssCOoLopp8XB4c= +github.com/llir/ll v0.0.0-20200414154635-a942fd56e775/go.mod h1:8W5HJz80PitAyPZUpOcljQxTu6LD5YKW1URTo+OjVoc= github.com/mewmew/float v0.0.0-20191226120903-16bbe2fdd85e h1:KCD7E/8LKwDsC5ymlEWJ3xCiSPaCywrS/psToBMOBH4= github.com/mewmew/float v0.0.0-20191226120903-16bbe2fdd85e/go.mod h1:O+xb+8ycBNHzJicFVs7GRWtruD4tVZI0huVnw5TM01E= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= diff --git a/ir/inst_other.go b/ir/inst_other.go index 5a470d8f..4d27c325 100644 --- a/ir/inst_other.go +++ b/ir/inst_other.go @@ -299,6 +299,59 @@ func (inst *InstSelect) LLString() string { return buf.String() } +// ~~~ [ freeze ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// InstFreeze is an LLVM IR freeze instruction. +type InstFreeze struct { + // Name of local variable associated with the result. + LocalIdent + // Operand. + X value.Value + // extra. + + // Type of result produced by the instruction. + Typ types.Type + // (optional) Metadata. + Metadata +} + +// NewInstFreeze returns a new freeze instruction based on the given +// operand. +func NewInstFreeze(x value.Value) *InstFreeze { + inst := &InstFreeze{X: x} + // Compute type. + inst.Type() + return inst +} + +// String returns the LLVM syntax representation of the instruction as a +// type-value pair. +func (inst *InstFreeze) String() string { + return fmt.Sprintf("%s %s", inst.Type(), inst.Ident()) +} + +// Type returns the type of the instruction. +func (inst *InstFreeze) Type() types.Type { + // Cache type if not present. + if inst.Typ == nil { + inst.Typ = inst.X.Type() + } + return inst.Typ +} + +// LLString returns the LLVM syntax representation of the instruction. +// +// 'freeze' Type Value +func (inst *InstFreeze) LLString() string { + buf := &strings.Builder{} + fmt.Fprintf(buf, "%s = ", inst.Ident()) + fmt.Fprintf(buf, "freeze %s", inst.X) + for _, md := range inst.Metadata { + fmt.Fprintf(buf, ", %s", md) + } + return buf.String() +} + // ~~~ [ call ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // InstCall is an LLVM IR call instruction. diff --git a/ir/instruction.go b/ir/instruction.go index c752e908..af9f102d 100644 --- a/ir/instruction.go +++ b/ir/instruction.go @@ -95,6 +95,7 @@ package ir // *ir.InstFCmp // https://godoc.org/github.com/llir/llvm/ir#InstFCmp // *ir.InstPhi // https://godoc.org/github.com/llir/llvm/ir#InstPhi // *ir.InstSelect // https://godoc.org/github.com/llir/llvm/ir#InstSelect +// *ir.InstFreeze // https://godoc.org/github.com/llir/llvm/ir#InstFreeze // *ir.InstCall // https://godoc.org/github.com/llir/llvm/ir#InstCall // *ir.InstVAArg // https://godoc.org/github.com/llir/llvm/ir#InstVAArg // *ir.InstLandingPad // https://godoc.org/github.com/llir/llvm/ir#InstLandingPad diff --git a/ir/sumtype.go b/ir/sumtype.go index ff5b9528..9cc31643 100644 --- a/ir/sumtype.go +++ b/ir/sumtype.go @@ -109,6 +109,7 @@ func (*InstICmp) isInstruction() {} func (*InstFCmp) isInstruction() {} func (*InstPhi) isInstruction() {} func (*InstSelect) isInstruction() {} +func (*InstFreeze) isInstruction() {} func (*InstCall) isInstruction() {} func (*InstVAArg) isInstruction() {} func (*InstLandingPad) isInstruction() {}