package llvm import "fmt" import "strings" // TODO add metadata type Instruction interface { LLString () string } type ValueInstruction interface { fmt.Stringer Instruction Value SetName (name string) } type AbstractInstructionBinary struct { Register Token string X, Y Value } func (this *AbstractInstructionBinary) LLString () string { buf := &strings.Builder { } if this.Named () { fmt.Fprintf(buf, "%s = ", this.Identifier()) } buf.WriteString(this.Token) fmt.Fprintf(buf, " %s, %s", this.X, this.Y.Identifier()) return buf.String() } type AbstractInstructionBinaryFP struct { AbstractInstructionBinary FastMathFlags []FastMathFlag } func (this *AbstractInstructionBinaryFP) LLString () string { buf := &strings.Builder{} fmt.Fprintf(buf, "%s = ", this.Identifier()) buf.WriteString(this.Token) for _, flag := range this.FastMathFlags { fmt.Fprintf(buf, " %s", flag) } fmt.Fprintf(buf, " %s, %s", this.X, this.Y.Identifier()) return buf.String() } type AbstractInstructionCast struct { Register Token string From Value To Type } func (this *AbstractInstructionCast) LLString () string { buf := &strings.Builder { } if this.Named () { fmt.Fprintf(buf, "%s = ", this.Identifier()) } buf.WriteString(this.Token) fmt.Fprintf(buf, " %s to %s", this.From, this.To) return buf.String() } type AbstractInstructionBinaryExact struct { AbstractInstructionBinary Exact bool } func (this *AbstractInstructionBinaryExact) LLString () string { buf := &strings.Builder { } if this.Named () { fmt.Fprintf(buf, "%s = ", this.Identifier()) } buf.WriteString(this.Token) if this.Exact { buf.WriteString(" exact") } fmt.Fprintf(buf, " %s, %s", this.X, this.Y.Identifier()) return buf.String() } type InstructionAShr struct { AbstractInstructionBinaryExact } func (this *Block) NewAShr (x, y Value) *InstructionAShr { instruction := &InstructionAShr { } instruction.Token = "ashr" instruction.X = x instruction.Y = y instruction.Ty = x.Type() this.AddInstruction(instruction) return instruction } type InstructionAdd struct { AbstractInstructionBinary } func (this *Block) NewAdd (x, y Value) *InstructionAdd { instruction := &InstructionAdd { } instruction.Token = "add" instruction.X = x instruction.Y = y instruction.Ty = x.Type() this.AddInstruction(instruction) return instruction } type InstructionAddrSpaceCast struct { AbstractInstructionCast } func (this *Block) NewAddrSpaceCast (from Value, to Type) *InstructionAddrSpaceCast { instruction := &InstructionAddrSpaceCast { } instruction.Token = "addrspacecast" instruction.From = from instruction.To = to instruction.Ty = to this.AddInstruction(instruction) return instruction } type InstructionAlloca struct { Register Element Type Count Value InAlloca bool Align Align AddressSpace AddressSpace } func (this *Block) NewAlloca (element Type) *InstructionAlloca { instruction := NewAlloca(element) this.AddInstruction(instruction) return instruction } func NewAlloca (element Type) *InstructionAlloca { instruction := &InstructionAlloca { Element: element, } ty := &TypePointer { } ty.AddressSpace = instruction.AddressSpace instruction.Ty = ty return instruction } func (this *InstructionAlloca) LLString () string { buf := &strings.Builder { } fmt.Fprintf(buf, "%s = ", this.Identifier()) buf.WriteString("alloca") if this.InAlloca { buf.WriteString(" inalloca") } fmt.Fprintf(buf, " %s", this.Element) if this.Count != nil { fmt.Fprintf(buf, ", %s", this.Count) } if this.Align != 0 { fmt.Fprintf(buf, ", %s", this.Align) } if this.AddressSpace != 0 { fmt.Fprintf(buf, ", %s", this.AddressSpace) } return buf.String() } type InstructionAnd struct { AbstractInstructionBinary } func (this *Block) NewAnd (x, y Value) *InstructionAnd { instruction := &InstructionAnd { } instruction.Token = "and" instruction.X = x instruction.Y = y instruction.Ty = x.Type() this.AddInstruction(instruction) return instruction } type AtomicOp uint8; const ( AtomicOpAdd AtomicOp = iota + 1 // add AtomicOpAnd // and AtomicOpFAdd // fadd AtomicOpFSub // fsub AtomicOpMax // max AtomicOpMin // min AtomicOpNAnd // nand AtomicOpOr // or AtomicOpSub // sub AtomicOpUMax // umax AtomicOpUMin // umin AtomicOpXChg // xchg AtomicOpXor // xor ) func (op AtomicOp) String () string { switch op { case AtomicOpAdd: return "add" case AtomicOpAnd: return "and" case AtomicOpFAdd: return "fadd" case AtomicOpFSub: return "fsub" case AtomicOpMax: return "max" case AtomicOpMin: return "min" case AtomicOpNAnd: return "nand" case AtomicOpOr: return "or" case AtomicOpSub: return "sub" case AtomicOpUMax: return "umax" case AtomicOpUMin: return "umin" case AtomicOpXChg: return "xchg" case AtomicOpXor: return "xor" default: return fmt.Sprintf("AtomicOp(%d)", op) } } type AtomicOrdering uint8; const ( // not_atomic AtomicOrderingNone AtomicOrdering = 0 // none AtomicOrderingUnordered AtomicOrdering = 1 // unordered AtomicOrderingMonotonic AtomicOrdering = 2 // monotonic //AtomicOrderingConsume AtomicOrdering = 3 // consume AtomicOrderingAcquire AtomicOrdering = 4 // acquire AtomicOrderingRelease AtomicOrdering = 5 // release AtomicOrderingAcquireRelease AtomicOrdering = 6 // acq_rel AtomicOrderingSequentiallyConsistent AtomicOrdering = 7 // seq_cst ) func (ordering AtomicOrdering) String () string { switch ordering { case AtomicOrderingNone: return "none" case AtomicOrderingUnordered: return "unordered" case AtomicOrderingMonotonic: return "monotonic" case AtomicOrderingAcquire: return "acquire" case AtomicOrderingRelease: return "release" case AtomicOrderingAcquireRelease: return "acq_rel" case AtomicOrderingSequentiallyConsistent: return "seq_cst" default: return fmt.Sprintf("AtomicOrdering(%d)", ordering) } } type InstructionAtomicRMW struct { Register Op AtomicOp Destination Value X Value Ordering AtomicOrdering Volatile bool SyncScope string } func (this *Block) NewAtomicRMW (op AtomicOp, destination, x Value, ordering AtomicOrdering) *InstructionAtomicRMW { instruction := &InstructionAtomicRMW { Op: op, Destination: destination, X: x, Ordering: ordering, } instruction.Ty = destination.Type() this.AddInstruction(instruction) return instruction } func (this *InstructionAtomicRMW) LLString () string { buf := &strings.Builder { } fmt.Fprintf(buf, "%s = ", this.Identifier()) buf.WriteString("atomicrmw") if this.Volatile { buf.WriteString(" volatile") } fmt.Fprintf(buf, " %s %s, %s", this.Op, this.Destination, this.X) if len(this.SyncScope) > 0 { fmt.Fprintf(buf, " syncscope(%s)", EscapeQuoteString([]byte(this.SyncScope))) } fmt.Fprintf(buf, " %s", this.Ordering) return buf.String() } type InstructionBitCast struct { Register From Value To Type } func (this *InstructionBitCast) LLString () string { buf := &strings.Builder { } if this.Named () { fmt.Fprintf(buf, "%s = ", this.Identifier()) } buf.WriteString("bitcast") fmt.Fprintf(buf, " %s to %s", this.From, this.To) return buf.String() } func (this *Block) NewBitCast (from Value, to Type) *InstructionBitCast { instruction := &InstructionBitCast { From: from, To: to } instruction.Ty = to this.AddInstruction(instruction) return instruction } type InstructionCall struct { Register Callee Value Signature *TypeFunction Arguments []Value AddressSpace AddressSpace // TODO complete this } func (this *InstructionCall) LLString () string { buf := &strings.Builder{} if _, ok := this.Type().(*TypeVoid); !ok { fmt.Fprintf(buf, "%s = ", this.Identifier()) } buf.WriteString("call") // (optional) Address space. if this.AddressSpace != 0 { fmt.Fprintf(buf, " %s", this.AddressSpace) } // Use function signature instead of return type for variadic functions. calleeType := this.Type() if sig := this.Signature; sig.Variadic { calleeType = sig } fmt.Fprintf(buf, " %s %s(", calleeType, this.Callee.Identifier()) for index, arg := range this.Arguments { if index > 0 { buf.WriteString(", ") } buf.WriteString(arg.String()) } buf.WriteString(")") return buf.String() } func (this *InstructionCall) Type () Type { return this.Signature.Return } func (this *Block) NewCall (callee Value, signature *TypeFunction, args ...Value) *InstructionCall { instruction := &InstructionCall { Callee: callee, Signature: signature, Arguments: args, } instruction.Ty = signature.Return this.AddInstruction(instruction) return instruction } type InstructionCatchPad struct { Register CatchSwitch Value Arguments []Value } func (this *InstructionCatchPad) LLString () string { buf := &strings.Builder{} fmt.Fprintf(buf, "%s = ", this.Identifier()) fmt.Fprintf(buf, "catchpad within %s [", this.CatchSwitch) for index, arg := range this.Arguments { if index > 0 { buf.WriteString(", ") } buf.WriteString(arg.String()) } buf.WriteString("]") return buf.String() } func (this *Block) NewCatchPad (catchSwitch Value, args ...Value) *InstructionCatchPad { instruction := &InstructionCatchPad { CatchSwitch: catchSwitch, Arguments: args, } instruction.Ty = &TypeToken { } this.AddInstruction(instruction) return instruction } type InstructionCleanupPad struct { Register ParentPad Value Arguments []Value } func (this *InstructionCleanupPad) LLString () string { buf := &strings.Builder{} fmt.Fprintf(buf, "%s = ", this.Identifier()) fmt.Fprintf(buf, "cleanuppad within %s [", this.ParentPad) for index, arg := range this.Arguments { if index > 0 { buf.WriteString(", ") } buf.WriteString(arg.String()) } buf.WriteString("]") return buf.String() } func (this *Block) NewCleanupPad (parentPad Value, args ...Value) *InstructionCleanupPad { instruction := &InstructionCleanupPad { ParentPad: parentPad, Arguments: args, } instruction.Ty = &TypeToken { } this.AddInstruction(instruction) return instruction } type InstructionCmpXchg struct { Register Source Value Against Value New Value SuccessOrdering AtomicOrdering FailureOrdering AtomicOrdering Weak bool Volatile bool SyncScope string } func (this *InstructionCmpXchg) LLString () string { buf := &strings.Builder{} fmt.Fprintf(buf, "%s = ", this.Identifier()) buf.WriteString("cmpxchg") if this.Weak { buf.WriteString(" weak") } if this.Volatile { buf.WriteString(" volatile") } fmt.Fprintf(buf, " %s, %s, %s", this.Source, this.Against, this.New) if len(this.SyncScope) > 0 { fmt.Fprintf(buf, " syncscope(%s)", EscapeQuoteString([]byte(this.SyncScope))) } fmt.Fprintf(buf, " %s", this.SuccessOrdering) fmt.Fprintf(buf, " %s", this.FailureOrdering) return buf.String() } func (this *Block) NewCmpXchg (source, against, neww Value, success, failure AtomicOrdering) *InstructionCmpXchg { instruction := &InstructionCmpXchg { Source: source, Against: against, New: neww, SuccessOrdering: success, FailureOrdering: failure, } instruction.Ty = &TypeStruct { Fields: []Type { neww.Type(), &TypeInt { BitSize: 1 }, }} this.AddInstruction(instruction) return instruction } type InstructionExtractElement struct { Register X Value Index Value } func (this *InstructionExtractElement) LLString () string { buf := &strings.Builder{} fmt.Fprintf(buf, "%s = ", this.Identifier()) fmt.Fprintf(buf, "extractelement %s, %s", this.X, this.Index) return buf.String() } func (this *Block) NewExtractElement (x, index Value) *InstructionExtractElement { instruction := &InstructionExtractElement { X: x, Index: index } instruction.Ty = x.Type().(*TypeVector).Element this.AddInstruction(instruction) return instruction } type InstructionExtractValue struct { Register X Value Indices []uint64 } func (this *InstructionExtractValue) LLString () string { buf := &strings.Builder { } fmt.Fprintf(buf, "%s = ", this.Identifier()) fmt.Fprintf(buf, "extractvalue %s", this.X) for _, index := range this.Indices { fmt.Fprintf(buf, ", %d", index) } return buf.String() } func (this *Block) NewExtractValue (x Value, indices ...uint64) *InstructionExtractValue { instruction := &InstructionExtractValue { X: x, Indices: indices, } instruction.Ty = aggregateElemType(x.Type(), indices) this.AddInstruction(instruction) return instruction } type FastMathFlag uint8; const ( FastMathFlagAFn FastMathFlag = iota // afn FastMathFlagARcp // arcp FastMathFlagContract // contract FastMathFlagFast // fast FastMathFlagNInf // ninf FastMathFlagNNaN // nnan FastMathFlagNSZ // nsz FastMathFlagReassoc // reassoc ) func (flag FastMathFlag) String () string { switch flag { case FastMathFlagAFn: return "afn" case FastMathFlagARcp: return "arcp" case FastMathFlagContract: return "contract" case FastMathFlagFast: return "fast" case FastMathFlagNInf: return "ninf" case FastMathFlagNNaN: return "nnan" case FastMathFlagNSZ: return "nsz" case FastMathFlagReassoc: return "reassoc" default: return fmt.Sprintf("FastMathFlag(%d)", flag) } } type InstructionFAdd struct { AbstractInstructionBinaryFP } func (this *Block) NewFAdd (x, y Value) *InstructionFAdd { instruction := &InstructionFAdd { } instruction.Token = "fadd" instruction.X = x instruction.Y = y instruction.Ty = x.Type() this.AddInstruction(instruction) return instruction } type FPredicate uint8; const ( FPredicateFalse FPredicate = iota // false FPredicateOEQ // oeq FPredicateOGE // oge FPredicateOGT // ogt FPredicateOLE // ole FPredicateOLT // olt FPredicateONE // one FPredicateORD // ord FPredicateTrue // true FPredicateUEQ // ueq FPredicateUGE // uge FPredicateUGT // ugt FPredicateULE // ule FPredicateULT // ult FPredicateUNE // une FPredicateUNO // uno ) func (predicate FPredicate) String () string { switch predicate { case FPredicateFalse: return "false" case FPredicateOEQ: return "oeq" case FPredicateOGE: return "oge" case FPredicateOGT: return "ogt" case FPredicateOLE: return "ole" case FPredicateOLT: return "olt" case FPredicateONE: return "one" case FPredicateORD: return "ord" case FPredicateTrue: return "true" case FPredicateUEQ: return "ueq" case FPredicateUGE: return "uge" case FPredicateUGT: return "ugt" case FPredicateULE: return "ule" case FPredicateULT: return "ult" case FPredicateUNE: return "une" case FPredicateUNO: return "uno" default: return fmt.Sprintf("FPredicate(%d)", predicate) } } type InstructionFCmp struct { AbstractInstructionBinaryFP Predicate FPredicate } func (this *InstructionFCmp) LLString () string { buf := &strings.Builder{} fmt.Fprintf(buf, "%s = ", this.Identifier()) buf.WriteString("fcmp") for _, flag := range this.FastMathFlags { fmt.Fprintf(buf, " %s", flag) } fmt.Fprintf(buf, " %s %s, %s", this.Predicate, this.X, this.Y.Identifier()) return buf.String() } func (this *Block) NewFCmp (predicate FPredicate, x, y Value) *InstructionFCmp { instruction := &InstructionFCmp { } instruction.Token = "fcmp" instruction.X = x instruction.Y = y instruction.Predicate = predicate switch xType := ReduceToBase(x.Type()).(type) { case *TypeFloat: instruction.Ty = &TypeInt { BitSize: 1 } case *TypeVector: instruction.Ty = &TypeVector { Length: xType.Length, Element: &TypeInt { BitSize: 1 }, } default: panic(fmt.Errorf("invalid fcmp operand type %T", xType)) } this.AddInstruction(instruction) return instruction } type InstructionFDiv struct { AbstractInstructionBinaryFP } func (this *Block) NewFDiv (x, y Value) *InstructionFDiv { instruction := &InstructionFDiv { } instruction.Token = "fdiv" instruction.X = x instruction.Y = y instruction.Ty = x.Type() this.AddInstruction(instruction) return instruction } type InstructionFMul struct { AbstractInstructionBinaryFP } func (this *Block) NewFMul (x, y Value) *InstructionFMul { instruction := &InstructionFMul { } instruction.Token = "fmul" instruction.X = x instruction.Y = y instruction.Ty = x.Type() this.AddInstruction(instruction) return instruction } type InstructionFNeg struct { Register X Value FastMathFlags []FastMathFlag } func (this *InstructionFNeg) LLString () string { buf := &strings.Builder{} fmt.Fprintf(buf, "%s = ", this.Identifier()) buf.WriteString("fneg") for _, flag := range this.FastMathFlags { fmt.Fprintf(buf, " %s", flag) } fmt.Fprintf(buf, " %s", this.X) return buf.String() } func (this *Block) NewFNeg (x Value) *InstructionFNeg { instruction := &InstructionFNeg { } instruction.X = x instruction.Ty = x.Type() this.AddInstruction(instruction) return instruction } type InstructionFPExt struct { AbstractInstructionCast } func (this *Block) NewFPExt (from Value, to Type) *InstructionFPExt { instruction := &InstructionFPExt { } instruction.Token = "fpext" instruction.From = from instruction.To = to instruction.Ty = to this.AddInstruction(instruction) return instruction } type InstructionFPToSI struct { AbstractInstructionCast } func (this *Block) NewFPToSI (from Value, to Type) *InstructionFPToSI { instruction := &InstructionFPToSI { } instruction.Token = "fptosi" instruction.From = from instruction.To = to instruction.Ty = to this.AddInstruction(instruction) return instruction } type InstructionFPToUI struct { AbstractInstructionCast } func (this *Block) NewFPToUI (from Value, to Type) *InstructionFPToUI { instruction := &InstructionFPToUI { } instruction.Token = "fptoui" instruction.From = from instruction.To = to instruction.Ty = to this.AddInstruction(instruction) return instruction } type InstructionFPTrunc struct { AbstractInstructionCast } func (this *Block) NewFPTrunc (from Value, to Type) *InstructionFPTrunc { instruction := &InstructionFPTrunc { } instruction.Token = "fptrunc" instruction.From = from instruction.To = to instruction.Ty = to this.AddInstruction(instruction) return instruction } type InstructionFRem struct { AbstractInstructionBinaryFP } func (this *Block) NewFRem (x, y Value) *InstructionFRem { instruction := &InstructionFRem { } instruction.Token = "frem" instruction.X = x instruction.Y = y instruction.Ty = x.Type() this.AddInstruction(instruction) return instruction } type InstructionFSub struct { AbstractInstructionBinaryFP } func (this *Block) NewFSub (x, y Value) *InstructionFSub { instruction := &InstructionFSub { } instruction.Token = "fsub" instruction.X = x instruction.Y = y instruction.Ty = x.Type() this.AddInstruction(instruction) return instruction } type InstructionFence struct { Ordering AtomicOrdering SyncScope string } func (this *InstructionFence) LLString () string { buf := &strings.Builder{} buf.WriteString("fence") if len(this.SyncScope) > 0 { fmt.Fprintf(buf, " syncscope(%s)", EscapeQuoteString([]byte(this.SyncScope))) } fmt.Fprintf(buf, " %s", this.Ordering) return buf.String() } func (this *Block) NewFence (ordering AtomicOrdering) *InstructionFence { instruction := &InstructionFence { Ordering: ordering } this.AddInstruction(instruction) return instruction } type InstructionFreeze struct { Register X Value } func (this *InstructionFreeze) LLString () string { buf := &strings.Builder{} fmt.Fprintf(buf, "%s = ", this.Identifier()) fmt.Fprintf(buf, "freeze %s", this.X) return buf.String() } func (this *Block) NewFreeze (x Value) *InstructionFreeze { instruction := &InstructionFreeze { X: x } instruction.Ty = x.Type() this.AddInstruction(instruction) return instruction } type InstructionGetElementPtr struct { Register Element Type Source Value Indices []Value InBounds bool } func (this *InstructionGetElementPtr) LLString () string { buf := &strings.Builder{} fmt.Fprintf(buf, "%s = ", this.Identifier()) buf.WriteString("getelementptr") if this.InBounds { buf.WriteString(" inbounds") } fmt.Fprintf(buf, " %s, %s", this.Element, this.Source) for _, index := range this.Indices { fmt.Fprintf(buf, ", %s", index) } return buf.String() } func (this *Block) NewGetElementPtr (element Type, source Value, indices ...Value) *InstructionGetElementPtr { instruction := &InstructionGetElementPtr { Element: element, Source: source, Indices: indices, } instruction.Ty = gepInstType(element, source.Type(), indices) this.AddInstruction(instruction) return instruction } type IPredicate uint8; const ( IPredicateEQ IPredicate = iota // eq IPredicateNE // ne IPredicateSGE // sge IPredicateSGT // sgt IPredicateSLE // sle IPredicateSLT // slt IPredicateUGE // uge IPredicateUGT // ugt IPredicateULE // ule IPredicateULT // ult ) func (predicate IPredicate) String () string { switch predicate { case IPredicateEQ: return "eq" case IPredicateNE: return "ne" case IPredicateSGE: return "sge" case IPredicateSGT: return "sgt" case IPredicateSLE: return "sle" case IPredicateSLT: return "slt" case IPredicateUGE: return "uge" case IPredicateUGT: return "ugt" case IPredicateULE: return "ule" case IPredicateULT: return "ult" default: return fmt.Sprintf("IPredicate(%d)", predicate) } } type InstructionICmp struct { AbstractInstructionBinary Predicate IPredicate } func (this *InstructionICmp) LLString () string { buf := &strings.Builder{} fmt.Fprintf(buf, "%s = ", this.Identifier()) buf.WriteString("icmp") fmt.Fprintf(buf, " %s %s, %s", this.Predicate, this.X, this.Y.Identifier()) return buf.String() } func (this *Block) NewICmp (predicate IPredicate, x, y Value) *InstructionICmp { instruction := &InstructionICmp { } instruction.Token = "icmp" instruction.X = x instruction.Y = y instruction.Predicate = predicate switch xType := ReduceToBase(x.Type()).(type) { case *TypeInt, *TypePointer: instruction.Ty = &TypeInt { BitSize: 1 } case *TypeVector: instruction.Ty = &TypeVector { Length: xType.Length, Element: &TypeInt { BitSize: 1 }, } default: panic(fmt.Errorf("invalid icmp operand type %T", xType)) } this.AddInstruction(instruction) return instruction } type InstructionInsertElement struct { Register X Value Element Value Index Value } func (this *InstructionInsertElement) LLString () string { buf := &strings.Builder{} fmt.Fprintf(buf, "%s = ", this.Identifier()) fmt.Fprintf(buf, "insertelement %s, %s, %s", this.X, this.Element, this.Index) return buf.String() } func (this *Block) NewInsertElement (x, element, index Value) *InstructionInsertElement { instruction := &InstructionInsertElement { X: x, Element: element, Index: index, } t, ok := x.Type().(*TypeVector) if !ok { panic(fmt.Errorf("invalid vector type %T", x.Type())) } instruction.Ty = t return instruction } type InstructionInsertValue struct { Register X Value Element Value Indices []uint64 } func (this *InstructionInsertValue) LLString () string { buf := &strings.Builder{} fmt.Fprintf(buf, "%s = ", this.Identifier()) fmt.Fprintf(buf, "insertvalue %s, %s", this.X, this.Element) for _, index := range this.Indices { fmt.Fprintf(buf, ", %d", index) } return buf.String() } func (this *Block) NewInsertValue (x, element Value, indices ...uint64) *InstructionInsertValue { instruction := &InstructionInsertValue { X: x, Element: element, Indices: indices, } instruction.Ty = x.Type() return instruction } type InstructionIntToPtr struct { AbstractInstructionCast } func (this *Block) NewIntToPtr (from Value, to Type) *InstructionIntToPtr { if to == nil { to = &TypePointer { } } instruction := &InstructionIntToPtr { } instruction.Token = "inttoptr" instruction.From = from instruction.To = to instruction.Ty = to this.AddInstruction(instruction) return instruction } type InstructionLShr struct { AbstractInstructionBinaryExact } func (this *Block) NewLShr (x, y Value) *InstructionLShr { instruction := &InstructionLShr { } instruction.Token = "lshr" instruction.X = x instruction.Y = y instruction.Ty = x.Type() this.AddInstruction(instruction) return instruction } type ClauseType uint8; const ( ClauseTypeCatch ClauseType = iota + 1 // catch ClauseTypeFilter // filter ) func (ty ClauseType) String () string { switch ty { case ClauseTypeCatch: return "catch" case ClauseTypeFilter: return "filter" default: return fmt.Sprintf("ClauseType(%d)", ty) } } type Clause struct { Type ClauseType X Value } func (this *Clause) String () string { return fmt.Sprintf("%s %s", this.Type, this.X) } type InstructionLandingPad struct { Register Cleanup bool Clauses []*Clause } func (this *InstructionLandingPad) LLString () string { buf := &strings.Builder{} fmt.Fprintf(buf, "%s = ", this.Identifier()) fmt.Fprintf(buf, "landingpad %s", this.Type()) if this.Cleanup { buf.WriteString("\n\t\tcleanup") } for _, clause := range this.Clauses { fmt.Fprintf(buf, "\n\t\t%s", clause) } return buf.String() } func (this *Block) NewLandingPad (result Type, clauses ...*Clause) *InstructionLandingPad { instruction := &InstructionLandingPad { Clauses: clauses } instruction.Ty = result this.AddInstruction(instruction) return instruction } type InstructionLoad struct { Register Source Value Atomic bool Volatile bool SyncScope string Ordering AtomicOrdering Align Align } func (this *InstructionLoad) LLString () string { buf := &strings.Builder{} fmt.Fprintf(buf, "%s = ", this.Identifier()) buf.WriteString("load") if this.Atomic { buf.WriteString(" atomic") } if this.Volatile { buf.WriteString(" volatile") } fmt.Fprintf(buf, " %s, %s", this.Type(), this.Source) if len(this.SyncScope) > 0 { fmt.Fprintf(buf, " syncscope(%s)", EscapeQuoteString([]byte(this.SyncScope))) } if this.Ordering != AtomicOrderingNone { fmt.Fprintf(buf, " %s", this.Ordering) } if this.Align != 0 { fmt.Fprintf(buf, ", %s", this.Align) } return buf.String() } func (this *Block) NewLoad (element Type, source Value) *InstructionLoad { instruction := &InstructionLoad { Source: source } instruction.Ty = element this.AddInstruction(instruction) return instruction } type OverflowFlag uint8; const ( OverflowFlagNSW OverflowFlag = iota // nsw OverflowFlagNUW // nuw ) func (flag OverflowFlag) String () string { switch flag { case OverflowFlagNSW: return "nsw" case OverflowFlagNUW: return "nuw" default: return fmt.Sprintf("OverflowFlag(%d)", flag) } } type InstructionMul struct { AbstractInstructionBinary OverflowFlags []OverflowFlag } func (this *InstructionMul) LLString () string { buf := &strings.Builder{} fmt.Fprintf(buf, "%s = ", this.Identifier()) buf.WriteString("mul") for _, flag := range this.OverflowFlags { fmt.Fprintf(buf, " %s", flag) } fmt.Fprintf(buf, " %s, %s", this.X, this.Y.Identifier()) return buf.String() } func (this *Block) NewMul (x, y Value) *InstructionMul { instruction := &InstructionMul { } instruction.Token = "mul" instruction.X = x instruction.Y = y instruction.Ty = x.Type() this.AddInstruction(instruction) return instruction } type InstructionOr struct { AbstractInstructionBinary } func (this *Block) NewOr (x, y Value) *InstructionOr { instruction := &InstructionOr { } instruction.Token = "or" instruction.X = x instruction.Y = y instruction.Ty = x.Type() this.AddInstruction(instruction) return instruction } type Incoming struct { X Value Predecessor Value } func (this *Incoming) String () string { return fmt.Sprintf("[ %s, %s ]", this.X.Identifier(), this.Predecessor.Identifier()) } type InstructionPhi struct { Register Incoming []*Incoming FastMathFlags []FastMathFlag } func (this *InstructionPhi) LLString () string { buf := &strings.Builder{} fmt.Fprintf(buf, "%s = ", this.Identifier()) buf.WriteString("phi ") for _, flag := range this.FastMathFlags { buf.WriteString(flag.String()) buf.WriteString(" ") } buf.WriteString(this.Type().String()) buf.WriteString(" ") for i, inc := range this.Incoming { if i != 0 { buf.WriteString(", ") } buf.WriteString(inc.String()) } return buf.String() } func (this *Block) NewPhi (incoming ...*Incoming) *InstructionPhi { instruction := &InstructionPhi { Incoming: incoming, } instruction.Ty = incoming[0].X.Type() this.AddInstruction(instruction) return instruction } type InstructionPtrToInt struct { AbstractInstructionCast } func (this *Block) NewPtrToInt (from Value, to Type) *InstructionPtrToInt { instruction := &InstructionPtrToInt { } instruction.Token = "ptrtoint" instruction.From = from instruction.To = to instruction.Ty = to this.AddInstruction(instruction) return instruction } type InstructionSDiv struct { AbstractInstructionBinary Exact bool } func (this *InstructionSDiv) LLString () string { buf := &strings.Builder { } if this.Named () { fmt.Fprintf(buf, "%s = ", this.Identifier()) } buf.WriteString("sdiv") if this.Exact { buf.WriteString(" exact") } fmt.Fprintf(buf, " %s, %s", this.X, this.Y.Identifier()) return buf.String() } func (this *Block) NewSDiv (x, y Value) *InstructionSDiv { instruction := &InstructionSDiv { } instruction.Token = "sdiv" instruction.X = x instruction.Y = y instruction.Ty = x.Type() this.AddInstruction(instruction) return instruction } type InstructionSExt struct { AbstractInstructionCast } func (this *Block) NewSExt (from Value, to Type) *InstructionSExt { instruction := &InstructionSExt { } instruction.Token = "sext" instruction.From = from instruction.To = to instruction.Ty = to this.AddInstruction(instruction) return instruction } type InstructionSIToFP struct { AbstractInstructionCast } func (this *Block) NewSIToFP (from Value, to Type) *InstructionSExt { instruction := &InstructionSExt { } instruction.Token = "sitofp" instruction.From = from instruction.To = to instruction.Ty = to this.AddInstruction(instruction) return instruction } type InstructionSRem struct { AbstractInstructionBinary } func (this *Block) NewSRem (x, y Value) *InstructionSRem { instruction := &InstructionSRem { } instruction.Token = "srem" instruction.X = x instruction.Y = y instruction.Ty = x.Type() this.AddInstruction(instruction) return instruction } type InstructionSelect struct { Register Condition Value True Value False Value FastMathFlags []FastMathFlag } func (this *InstructionSelect) LLString() string { buf := &strings.Builder{} fmt.Fprintf(buf, "%s = ", this.Identifier()) buf.WriteString("select") for _, flag := range this.FastMathFlags { fmt.Fprintf(buf, " %s", flag) } fmt.Fprintf(buf, " %s, %s, %s", this.Condition, this.True, this.False) return buf.String() } func (this *Block) NewSelect (condition, tru, fals Value) *InstructionSelect { instruction := &InstructionSelect { Condition: condition, True: tru, False: fals, } instruction.Ty = tru.Type() return instruction } type InstructionShl struct { AbstractInstructionBinary OverflowFlags []OverflowFlag } func (this *InstructionShl) LLString () string { buf := &strings.Builder{} fmt.Fprintf(buf, "%s = ", this.Identifier()) buf.WriteString("shl") for _, flag := range this.OverflowFlags { fmt.Fprintf(buf, " %s", flag) } fmt.Fprintf(buf, " %s, %s", this.X, this.Y.Identifier()) return buf.String() } func (this *Block) NewShl (x, y Value) *InstructionShl { instruction := &InstructionShl { } instruction.Token = "shl" instruction.X = x instruction.Y = y instruction.Ty = x.Type() this.AddInstruction(instruction) return instruction } type InstructionShuffleVector struct { Register X, Y Value Mask Value } func (this *InstructionShuffleVector) LLString () string { buf := &strings.Builder{} fmt.Fprintf(buf, "%s = ", this.Identifier()) fmt.Fprintf(buf, "shufflevector %s, %s, %s", this.X, this.Y, this.Mask) return buf.String() } func (this *Block) NewShuffleVector (x, y, mask Value) *InstructionShuffleVector { instruction := &InstructionShuffleVector { X: x, Y: y, Mask: mask, } xType, ok := x.Type().(*TypeVector) if !ok { panic(fmt.Errorf("invalid vector type %T", x.Type())) } maskType, ok := mask.Type().(*TypeVector) if !ok { panic(fmt.Errorf("invalid vector type %T", mask.Type())) } instruction.Ty = &TypeVector { Length: maskType.Length, Element: xType.Element, } this.AddInstruction(instruction) return instruction } type InstructionStore struct { Source, Destination Value Atomic bool Volatile bool SyncScope string Ordering AtomicOrdering Align Align } func (this *InstructionStore) LLString () string { buf := &strings.Builder{} buf.WriteString("store") if this.Atomic { buf.WriteString(" atomic") } if this.Volatile { buf.WriteString(" volatile") } fmt.Fprintf(buf, " %s, %s", this.Source, this.Destination) if len(this.SyncScope) > 0 { fmt.Fprintf(buf, " syncscope(%s)", EscapeQuoteString([]byte(this.SyncScope))) } if this.Ordering != AtomicOrderingNone { fmt.Fprintf(buf, " %s", this.Ordering) } if this.Align != 0 { fmt.Fprintf(buf, ", %s", this.Align) } return buf.String() } func (this *Block) NewStore (source, destination Value) *InstructionStore { instruction := &InstructionStore { Source: source, Destination: destination, } this.AddInstruction(instruction) return instruction } type InstructionSub struct { AbstractInstructionBinary OverflowFlags []OverflowFlag } func (this *InstructionSub) LLString () string { buf := &strings.Builder{} fmt.Fprintf(buf, "%s = ", this.Identifier()) buf.WriteString("sub") for _, flag := range this.OverflowFlags { fmt.Fprintf(buf, " %s", flag) } fmt.Fprintf(buf, " %s, %s", this.X, this.Y.Identifier()) return buf.String() } func (this *Block) NewSub (x, y Value) *InstructionSub { instruction := &InstructionSub { } instruction.Token = "sub" instruction.X = x instruction.Y = y instruction.Ty = x.Type() this.AddInstruction(instruction) return instruction } type InstructionTrunc struct { AbstractInstructionCast } func (this *Block) NewTrunc (from Value, to Type) *InstructionTrunc { instruction := &InstructionTrunc { } instruction.Token = "trunc" instruction.From = from instruction.To = to instruction.Ty = to this.AddInstruction(instruction) return instruction } type InstructionUDiv struct { AbstractInstructionBinaryExact } func (this *Block) NewUDiv (x, y Value) *InstructionUDiv { instruction := &InstructionUDiv { } instruction.Token = "udiv" instruction.X = x instruction.Y = y instruction.Ty = x.Type() this.AddInstruction(instruction) return instruction } type InstructionUIToFP struct { AbstractInstructionCast } func (this *Block) NewUIToFP (from Value, to Type) *InstructionUIToFP { instruction := &InstructionUIToFP { } instruction.Token = "uitofp" instruction.From = from instruction.To = to instruction.Ty = to this.AddInstruction(instruction) return instruction } type InstructionURem struct { AbstractInstructionBinary } func (this *Block) NewURem (x, y Value) *InstructionURem { instruction := &InstructionURem { } instruction.Token = "urem" instruction.X = x instruction.Y = y instruction.Ty = x.Type() this.AddInstruction(instruction) return instruction } type InstructionVAArg struct { Register List Value } func (this *InstructionVAArg) LLString() string { buf := &strings.Builder{} fmt.Fprintf(buf, "%s = ", this.Identifier()) fmt.Fprintf(buf, "va_arg %s, %s", this.List, this.Type()) return buf.String() } func (this *Block) NewVAArg (list Value, ty Type) *InstructionVAArg { instruction := &InstructionVAArg { List: list } instruction.Ty = ty this.AddInstruction(instruction) return instruction } type InstructionXor struct { AbstractInstructionBinary } func (this *Block) NewXor (x, y Value) *InstructionXor { instruction := &InstructionXor { } instruction.Token = "xor" instruction.X = x instruction.Y = y instruction.Ty = x.Type() this.AddInstruction(instruction) return instruction } type InstructionZext struct { AbstractInstructionCast } func (this *Block) NewZext (from Value, to Type) *InstructionZext { instruction := &InstructionZext { } instruction.Token = "zext" instruction.From = from instruction.To = to instruction.Ty = to this.AddInstruction(instruction) return instruction }