| /* |
| * Copyright (C) 2016 Apple Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| "use strict"; |
| |
| class Arg { |
| constructor() |
| { |
| this._kind = Arg.Invalid; |
| } |
| |
| static isAnyUse(role) |
| { |
| switch (role) { |
| case Arg.Use: |
| case Arg.ColdUse: |
| case Arg.UseDef: |
| case Arg.UseZDef: |
| case Arg.LateUse: |
| case Arg.LateColdUse: |
| case Arg.Scratch: |
| return true; |
| case Arg.Def: |
| case Arg.ZDef: |
| case Arg.UseAddr: |
| case Arg.EarlyDef: |
| return false; |
| default: |
| throw new Error("Bad role"); |
| } |
| } |
| |
| static isColdUse(role) |
| { |
| switch (role) { |
| case Arg.ColdUse: |
| case Arg.LateColdUse: |
| return true; |
| case Arg.Use: |
| case Arg.UseDef: |
| case Arg.UseZDef: |
| case Arg.LateUse: |
| case Arg.Def: |
| case Arg.ZDef: |
| case Arg.UseAddr: |
| case Arg.Scratch: |
| case Arg.EarlyDef: |
| return false; |
| default: |
| throw new Error("Bad role"); |
| } |
| } |
| |
| static isWarmUse(role) |
| { |
| return Arg.isAnyUse(role) && !Arg.isColdUse(role); |
| } |
| |
| static cooled(role) |
| { |
| switch (role) { |
| case Arg.ColdUse: |
| case Arg.LateColdUse: |
| case Arg.UseDef: |
| case Arg.UseZDef: |
| case Arg.Def: |
| case Arg.ZDef: |
| case Arg.UseAddr: |
| case Arg.Scratch: |
| case Arg.EarlyDef: |
| return role; |
| case Arg.Use: |
| return Arg.ColdUse; |
| case Arg.LateUse: |
| return Arg.LateColdUse; |
| default: |
| throw new Error("Bad role"); |
| } |
| } |
| |
| static isEarlyUse(role) |
| { |
| switch (role) { |
| case Arg.Use: |
| case Arg.ColdUse: |
| case Arg.UseDef: |
| case Arg.UseZDef: |
| return true; |
| case Arg.Def: |
| case Arg.ZDef: |
| case Arg.UseAddr: |
| case Arg.LateUse: |
| case Arg.LateColdUse: |
| case Arg.Scratch: |
| case Arg.EarlyDef: |
| return false; |
| default: |
| throw new Error("Bad role"); |
| } |
| } |
| |
| static isLateUse(role) |
| { |
| switch (role) { |
| case Arg.LateUse: |
| case Arg.LateColdUse: |
| case Arg.Scratch: |
| return true; |
| case Arg.ColdUse: |
| case Arg.Use: |
| case Arg.UseDef: |
| case Arg.UseZDef: |
| case Arg.Def: |
| case Arg.ZDef: |
| case Arg.UseAddr: |
| case Arg.EarlyDef: |
| return false; |
| default: |
| throw new Error("Bad role"); |
| } |
| } |
| |
| static isAnyDef(role) |
| { |
| switch (role) { |
| case Arg.Use: |
| case Arg.ColdUse: |
| case Arg.UseAddr: |
| case Arg.LateUse: |
| case Arg.LateColdUse: |
| return false; |
| case Arg.Def: |
| case Arg.UseDef: |
| case Arg.ZDef: |
| case Arg.UseZDef: |
| case Arg.EarlyDef: |
| case Arg.Scratch: |
| return true; |
| default: |
| throw new Error("Bad role"); |
| } |
| } |
| |
| static isEarlyDef(role) |
| { |
| switch (role) { |
| case Arg.Use: |
| case Arg.ColdUse: |
| case Arg.UseAddr: |
| case Arg.LateUse: |
| case Arg.Def: |
| case Arg.UseDef: |
| case Arg.ZDef: |
| case Arg.UseZDef: |
| case Arg.LateColdUse: |
| return false; |
| case Arg.EarlyDef: |
| case Arg.Scratch: |
| return true; |
| default: |
| throw new Error("Bad role"); |
| } |
| } |
| |
| static isLateDef(role) |
| { |
| switch (role) { |
| case Arg.Use: |
| case Arg.ColdUse: |
| case Arg.UseAddr: |
| case Arg.LateUse: |
| case Arg.EarlyDef: |
| case Arg.Scratch: |
| case Arg.LateColdUse: |
| return false; |
| case Arg.Def: |
| case Arg.UseDef: |
| case Arg.ZDef: |
| case Arg.UseZDef: |
| return true; |
| default: |
| throw new Error("Bad role"); |
| } |
| } |
| |
| static isZDef(role) |
| { |
| switch (role) { |
| case Arg.Use: |
| case Arg.ColdUse: |
| case Arg.UseAddr: |
| case Arg.LateUse: |
| case Arg.Def: |
| case Arg.UseDef: |
| case Arg.EarlyDef: |
| case Arg.Scratch: |
| case Arg.LateColdUse: |
| return false; |
| case Arg.ZDef: |
| case Arg.UseZDef: |
| return true; |
| default: |
| throw new Error("Bad role"); |
| } |
| } |
| |
| static typeForB3Type(type) |
| { |
| switch (type) { |
| case Int32: |
| case Int64: |
| return GP; |
| case Float: |
| case Double: |
| return FP; |
| default: |
| throw new Error("Bad B3 type"); |
| } |
| } |
| |
| static widthForB3Type(type) |
| { |
| switch (type) { |
| case Int32: |
| case Float: |
| return 32; |
| case Int64: |
| case Double: |
| return 64; |
| default: |
| throw new Error("Bad B3 type"); |
| } |
| } |
| |
| static conservativeWidth(type) |
| { |
| return type == GP ? Ptr : 64; |
| } |
| |
| static minimumWidth(type) |
| { |
| return type == GP ? 8 : 32; |
| } |
| |
| static bytes(width) |
| { |
| return width / 8; |
| } |
| |
| static widthForBytes(bytes) |
| { |
| switch (bytes) { |
| case 0: |
| case 1: |
| return 8; |
| case 2: |
| return 16; |
| case 3: |
| case 4: |
| return 32; |
| default: |
| if (bytes > 8) |
| throw new Error("Bad number of bytes"); |
| return 64; |
| } |
| } |
| |
| static createTmp(tmp) |
| { |
| let result = new Arg(); |
| result._kind = Arg.Tmp; |
| result._tmp = tmp; |
| return result; |
| } |
| |
| static fromReg(reg) |
| { |
| return Arg.createTmp(reg); |
| } |
| |
| static createImm(value) |
| { |
| let result = new Arg(); |
| result._kind = Arg.Imm; |
| result._value = value; |
| return result; |
| } |
| |
| static createBigImm(lowValue, highValue = 0) |
| { |
| let result = new Arg(); |
| result._kind = Arg.BigImm; |
| result._lowValue = lowValue; |
| result._highValue = highValue; |
| return result; |
| } |
| |
| static createBitImm(value) |
| { |
| let result = new Arg(); |
| result._kind = Arg.BitImm; |
| result._value = value; |
| return result; |
| } |
| |
| static createBitImm64(lowValue, highValue = 0) |
| { |
| let result = new Arg(); |
| result._kind = Arg.BitImm64; |
| result._lowValue = lowValue; |
| result._highValue = highValue; |
| return result; |
| } |
| |
| static createAddr(base, offset = 0) |
| { |
| let result = new Arg(); |
| result._kind = Arg.Addr; |
| result._base = base; |
| result._offset = offset; |
| return result; |
| } |
| |
| static createStack(slot, offset = 0) |
| { |
| let result = new Arg(); |
| result._kind = Arg.Stack; |
| result._slot = slot; |
| result._offset = offset; |
| return result; |
| } |
| |
| static createCallArg(offset) |
| { |
| let result = new Arg(); |
| result._kind = Arg.CallArg; |
| result._offset = offset; |
| return result; |
| } |
| |
| static createStackAddr(offsetFromFP, frameSize, width) |
| { |
| let result = Arg.createAddr(Reg.callFrameRegister, offsetFromFP); |
| if (!result.isValidForm(width)) |
| result = Arg.createAddr(Reg.stackPointerRegister, offsetFromFP + frameSize); |
| return result; |
| } |
| |
| static isValidScale(scale, width) |
| { |
| switch (scale) { |
| case 1: |
| case 2: |
| case 4: |
| case 8: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| static logScale(scale) |
| { |
| switch (scale) { |
| case 1: |
| return 0; |
| case 2: |
| return 1; |
| case 4: |
| return 2; |
| case 8: |
| return 3; |
| default: |
| throw new Error("Bad scale"); |
| } |
| } |
| |
| static createIndex(base, index, scale = 1, offset = 0) |
| { |
| let result = new Arg(); |
| result._kind = Arg.Index; |
| result._base = base; |
| result._index = index; |
| result._scale = scale; |
| result._offset = offset; |
| return result; |
| } |
| |
| static createRelCond(condition) |
| { |
| let result = new Arg(); |
| result._kind = Arg.RelCond; |
| result._condition = condition; |
| return result; |
| } |
| |
| static createResCond(condition) |
| { |
| let result = new Arg(); |
| result._kind = Arg.ResCond; |
| result._condition = condition; |
| return result; |
| } |
| |
| static createDoubleCond(condition) |
| { |
| let result = new Arg(); |
| result._kind = Arg.DoubleCond; |
| result._condition = condition; |
| return result; |
| } |
| |
| static createWidth(width) |
| { |
| let result = new Arg(); |
| result._kind = Arg.Width; |
| result._width = width; |
| return result; |
| } |
| |
| static createSpecial() |
| { |
| let result = new Arg(); |
| result._kind = Arg.Special; |
| return result; |
| } |
| |
| get kind() { return this._kind; } |
| get isTmp() { return this._kind == Arg.Tmp; } |
| get isImm() { return this._kind == Arg.Imm; } |
| get isBigImm() { return this._kind == Arg.BigImm; } |
| get isBitImm() { return this._kind == Arg.BitImm; } |
| get isBitImm64() { return this._kind == Arg.BitImm64; } |
| get isSomeImm() |
| { |
| switch (this._kind) { |
| case Arg.Imm: |
| case Arg.BitImm: |
| return true; |
| default: |
| return false; |
| } |
| } |
| get isSomeBigImm() |
| { |
| switch (this._kind) { |
| case Arg.BigImm: |
| case Arg.BitImm64: |
| return true; |
| default: |
| return false; |
| } |
| } |
| get isAddr() { return this._kind == Arg.Addr; } |
| get isStack() { return this._kind == Arg.Stack; } |
| get isCallArg() { return this._kind == Arg.CallArg; } |
| get isIndex() { return this._kind == Arg.Index; } |
| get isMemory() |
| { |
| switch (this._kind) { |
| case Arg.Addr: |
| case Arg.Stack: |
| case Arg.CallArg: |
| case Arg.Index: |
| return true; |
| default: |
| return false; |
| } |
| } |
| get isStackMemory() |
| { |
| switch (this._kind) { |
| case Arg.Addr: |
| return this._base == Reg.callFrameRegister |
| || this._base == Reg.stackPointerRegister; |
| case Arg.Stack: |
| case Arg.CallArg: |
| return true; |
| default: |
| return false; |
| } |
| } |
| get isRelCond() { return this._kind == Arg.RelCond; } |
| get isResCond() { return this._kind == Arg.ResCond; } |
| get isDoubleCond() { return this._kind == Arg.DoubleCond; } |
| get isCondition() |
| { |
| switch (this._kind) { |
| case Arg.RelCond: |
| case Arg.ResCond: |
| case Arg.DoubleCond: |
| return true; |
| default: |
| return false; |
| } |
| } |
| get isWidth() { return this._kind == Arg.Width; } |
| get isSpecial() { return this._kind == Arg.Special; } |
| get isAlive() { return this.isTmp || this.isStack; } |
| |
| get tmp() |
| { |
| if (this._kind != Arg.Tmp) |
| throw new Error("Called .tmp for non-tmp"); |
| return this._tmp; |
| } |
| |
| get value() |
| { |
| if (!this.isSomeImm) |
| throw new Error("Called .value for non-imm"); |
| return this._value; |
| } |
| |
| get lowValue() |
| { |
| if (!this.isSomeBigImm) |
| throw new Error("Called .lowValue for non-big-imm"); |
| return this._lowValue; |
| } |
| |
| get highValue() |
| { |
| if (!this.isSomeBigImm) |
| throw new Error("Called .highValue for non-big-imm"); |
| return this._highValue; |
| } |
| |
| get base() |
| { |
| switch (this._kind) { |
| case Arg.Addr: |
| case Arg.Index: |
| return this._base; |
| default: |
| throw new Error("Called .base for non-address"); |
| } |
| } |
| |
| get hasOffset() { return this.isMemory; } |
| |
| get offset() |
| { |
| switch (this._kind) { |
| case Arg.Addr: |
| case Arg.Index: |
| case Arg.Stack: |
| case Arg.CallArg: |
| return this._offset; |
| default: |
| throw new Error("Called .offset for non-address"); |
| } |
| } |
| |
| get stackSlot() |
| { |
| if (this._kind != Arg.Stack) |
| throw new Error("Called .stackSlot for non-address"); |
| return this._slot; |
| } |
| |
| get index() |
| { |
| if (this._kind != Arg.Index) |
| throw new Error("Called .index for non-Index"); |
| return this._index; |
| } |
| |
| get scale() |
| { |
| if (this._kind != Arg.Index) |
| throw new Error("Called .scale for non-Index"); |
| return this._scale; |
| } |
| |
| get logScale() |
| { |
| return Arg.logScale(this.scale); |
| } |
| |
| get width() |
| { |
| if (this._kind != Arg.Width) |
| throw new Error("Called .width for non-Width"); |
| return this._width; |
| } |
| |
| get isGPTmp() { return this.isTmp && this.tmp.isGP; } |
| get isFPTmp() { return this.isTmp && this.tmp.isFP; } |
| |
| get isGP() |
| { |
| switch (this._kind) { |
| case Arg.Imm: |
| case Arg.BigImm: |
| case Arg.BitImm: |
| case Arg.BitImm64: |
| case Arg.Addr: |
| case Arg.Index: |
| case Arg.Stack: |
| case Arg.CallArg: |
| case Arg.RelCond: |
| case Arg.ResCond: |
| case Arg.DoubleCond: |
| case Arg.Width: |
| case Arg.Special: |
| return true; |
| case Arg.Tmp: |
| return this.isGPTmp; |
| case Arg.Invalid: |
| return false; |
| default: |
| throw new Error("Bad kind"); |
| } |
| } |
| |
| get isFP() |
| { |
| switch (this._kind) { |
| case Arg.Imm: |
| case Arg.BitImm: |
| case Arg.BitImm64: |
| case Arg.RelCond: |
| case Arg.ResCond: |
| case Arg.DoubleCond: |
| case Arg.Width: |
| case Arg.Special: |
| case Arg.Invalid: |
| return false; |
| case Arg.Addr: |
| case Arg.Index: |
| case Arg.Stack: |
| case Arg.CallArg: |
| case Arg.BigImm: |
| return true; |
| case Arg.Tmp: |
| return this.isFPTmp; |
| default: |
| throw new Error("Bad kind"); |
| } |
| } |
| |
| get hasType() |
| { |
| switch (this._kind) { |
| case Arg.Imm: |
| case Arg.BitImm: |
| case Arg.BitImm64: |
| case Arg.Tmp: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| get type() |
| { |
| return this.isGP ? GP : FP; |
| } |
| |
| isType(type) |
| { |
| switch (type) { |
| case Arg.GP: |
| return this.isGP; |
| case Arg.FP: |
| return this.isFP; |
| default: |
| throw new Error("Bad type"); |
| } |
| } |
| |
| isCompatibleType(other) |
| { |
| if (this.hasType) |
| return other.isType(this.type); |
| if (other.hasType) |
| return this.isType(other.type); |
| return true; |
| } |
| |
| get isGPR() { return this.isTmp && this.tmp.isGPR; } |
| get gpr() { return this.tmp.gpr; } |
| get isFPR() { return this.isTmp && this.tmp.isFPR; } |
| get fpr() { return this.tmp.fpr; } |
| get isReg() { return this.isTmp && this.tmp.isReg; } |
| get reg() { return this.tmp.reg; } |
| |
| static isValidImmForm(value) |
| { |
| return isRepresentableAsInt32(value); |
| } |
| static isValidBitImmForm(value) |
| { |
| return isRepresentableAsInt32(value); |
| } |
| static isValidBitImm64Form(value) |
| { |
| return isRepresentableAsInt32(value); |
| } |
| |
| static isValidAddrForm(offset, width) |
| { |
| return true; |
| } |
| |
| static isValidIndexForm(scale, offset, width) |
| { |
| if (!isValidScale(scale, width)) |
| return false; |
| return true; |
| } |
| |
| isValidForm(width) |
| { |
| switch (this._kind) { |
| case Arg.Invalid: |
| return false; |
| case Arg.Tmp: |
| return true; |
| case Arg.Imm: |
| return Arg.isValidImmForm(this.value); |
| case Arg.BigImm: |
| return true; |
| case Arg.BitImm: |
| return Arg.isValidBitImmForm(this.value); |
| case Arg.BitImm64: |
| return Arg.isValidBitImm64Form(this.value); |
| case Arg.Addr: |
| case Arg.Stack: |
| case Arg.CallArg: |
| return Arg.isValidAddrForm(this.offset, width); |
| case Arg.Index: |
| return Arg.isValidIndexForm(this.scale, this.offset, width); |
| case Arg.RelCond: |
| case Arg.ResCond: |
| case Arg.DoubleCond: |
| case Arg.Width: |
| case Arg.Special: |
| return true; |
| default: |
| throw new Error("Bad kind"); |
| } |
| } |
| |
| forEachTmpFast(func) |
| { |
| switch (this._kind) { |
| case Arg.Tmp: { |
| let replacement; |
| if (replacement = func(this._tmp)) |
| return Arg.createTmp(replacement); |
| break; |
| } |
| case Arg.Addr: { |
| let replacement; |
| if (replacement = func(this._base)) |
| return Arg.createAddr(replacement, this._offset); |
| break; |
| } |
| case Arg.Index: { |
| let baseReplacement = func(this._base); |
| let indexReplacement = func(this._index); |
| if (baseReplacement || indexReplacement) { |
| return Arg.createIndex( |
| baseReplacement ? baseReplacement : this._base, |
| indexReplacement ? indexReplacement : this._index, |
| this._scale, this._offset); |
| } |
| break; |
| } |
| default: |
| break; |
| } |
| } |
| |
| usesTmp(expectedTmp) |
| { |
| let usesTmp = false; |
| forEachTmpFast(tmp => { |
| usesTmp |= tmp == expectedTmp; |
| }); |
| return usesTmp; |
| } |
| |
| forEachTmp(role, type, width, func) |
| { |
| switch (this._kind) { |
| case Arg.Tmp: { |
| let replacement; |
| if (replacement = func(this._tmp, role, type, width)) |
| return Arg.createTmp(replacement); |
| break; |
| } |
| case Arg.Addr: { |
| let replacement; |
| if (replacement = func(this._base, Arg.Use, GP, role == Arg.UseAddr ? width : Ptr)) |
| return Arg.createAddr(replacement, this._offset); |
| break; |
| } |
| case Arg.Index: { |
| let baseReplacement = func(this._base, Arg.Use, GP, role == Arg.UseAddr ? width : Ptr); |
| let indexReplacement = func(this._index, Arg.Use, GP, role == Arg.UseAddr ? width : Ptr); |
| if (baseReplacement || indexReplacement) { |
| return Arg.createIndex( |
| baseReplacement ? baseReplacement : this._base, |
| indexReplacement ? indexReplacement : this._index, |
| this._scale, this._offset); |
| } |
| break; |
| } |
| default: |
| break; |
| } |
| } |
| |
| is(thing) { return !!thing.extract(this); } |
| as(thing) { return thing.extract(this); } |
| |
| // This lets you say things like: |
| // arg.forEach(Tmp | Reg | Arg | StackSlot, ...) |
| // |
| // It's used for abstract liveness analysis. |
| forEachFast(thing, func) |
| { |
| return thing.forEachFast(this, func); |
| } |
| forEach(thing, role, type, width, func) |
| { |
| return thing.forEach(this, role, type, width, func); |
| } |
| |
| static extract(arg) { return arg; } |
| static forEachFast(arg, func) { return func(arg); } |
| static forEach(arg, role, type, width, func) { return func(arg, role, type, width); } |
| |
| get condition() |
| { |
| switch (this._kind) { |
| case Arg.RelCond: |
| case Arg.ResCond: |
| case Arg.DoubleCond: |
| return this._condition; |
| default: |
| throw new Error("Called .condition for non-condition"); |
| } |
| } |
| |
| get isInvertible() |
| { |
| switch (this._kind) { |
| case Arg.RelCond: |
| case Arg.DoubleCold: |
| return true; |
| case Arg.ResCond: |
| switch (this._condition) { |
| case Zero: |
| case NonZero: |
| case Signed: |
| case PositiveOrZero: |
| return true; |
| default: |
| return false; |
| } |
| default: |
| return false; |
| } |
| } |
| |
| static kindCode(kind) |
| { |
| switch (kind) { |
| case Arg.Invalid: |
| return 0; |
| case Arg.Tmp: |
| return 1; |
| case Arg.Imm: |
| return 2; |
| case Arg.BigImm: |
| return 3; |
| case Arg.BitImm: |
| return 4; |
| case Arg.BitImm64: |
| return 5; |
| case Arg.Addr: |
| return 6; |
| case Arg.Stack: |
| return 7; |
| case Arg.CallArg: |
| return 8; |
| case Arg.Index: |
| return 9; |
| case Arg.RelCond: |
| return 10; |
| case Arg.ResCond: |
| return 11; |
| case Arg.DoubleCond: |
| return 12; |
| case Arg.Special: |
| return 13; |
| case Arg.WidthArg: |
| return 14; |
| default: |
| throw new Error("Bad kind"); |
| } |
| } |
| |
| hash() |
| { |
| let result = Arg.kindCode(this._kind); |
| |
| switch (this._kind) { |
| case Arg.Invalid: |
| case Arg.Special: |
| break; |
| case Arg.Tmp: |
| result += this._tmp.hash(); |
| result |= 0; |
| break; |
| case Arg.Imm: |
| case Arg.BitImm: |
| result += this._value; |
| result |= 0; |
| break; |
| case Arg.BigImm: |
| case Arg.BitImm64: |
| result += this._lowValue; |
| result |= 0; |
| result += this._highValue; |
| result |= 0; |
| break; |
| case Arg.CallArg: |
| result += this._offset; |
| result |= 0; |
| break; |
| case Arg.RelCond: |
| result += relCondCode(this._condition); |
| result |= 0; |
| break; |
| case Arg.ResCond: |
| result += resCondCode(this._condition); |
| result |= 0; |
| break; |
| case Arg.DoubleCond: |
| result += doubleCondCode(this._condition); |
| result |= 0; |
| break; |
| case Arg.WidthArg: |
| result += this._width; |
| result |= 0; |
| break; |
| case Arg.Addr: |
| result += this._offset; |
| result |= 0; |
| result += this._base.hash(); |
| result |= 0; |
| break; |
| case Arg.Index: |
| result += this._offset; |
| result |= 0; |
| result += this._scale; |
| result |= 0; |
| result += this._base.hash(); |
| result |= 0; |
| result += this._index.hash(); |
| result |= 0; |
| break; |
| case Arg.Stack: |
| result += this._offset; |
| result |= 0; |
| result += this.stackSlot.index; |
| result |= 0; |
| break; |
| } |
| |
| return result >>> 0; |
| } |
| |
| toString() |
| { |
| switch (this._kind) { |
| case Arg.Invalid: |
| return "<invalid>"; |
| case Arg.Tmp: |
| return this._tmp.toString(); |
| case Arg.Imm: |
| return "$" + this._value; |
| case Arg.BigImm: |
| case Arg.BitImm64: |
| return "$0x" + this._highValue.toString(16) + ":" + this._lowValue.toString(16); |
| case Arg.Addr: |
| return "" + (this._offset ? this._offset : "") + "(" + this._base + ")"; |
| case Arg.Index: |
| return "" + (this._offset ? this._offset : "") + "(" + this._base + |
| "," + this._index + (this._scale == 1 ? "" : "," + this._scale) + ")"; |
| case Arg.Stack: |
| return "" + (this._offset ? this._offset : "") + "(" + this._slot + ")"; |
| case Arg.CallArg: |
| return "" + (this._offset ? this._offset : "") + "(callArg)"; |
| case Arg.RelCond: |
| case Arg.ResCond: |
| case Arg.DoubleCond: |
| return symbolName(this._condition); |
| case Arg.Special: |
| return "special"; |
| case Arg.Width: |
| return "" + this._value; |
| default: |
| throw new Error("Bad kind"); |
| } |
| } |
| } |
| |
| // Arg kinds |
| Arg.Invalid = Symbol("Invalid"); |
| Arg.Tmp = Symbol("Tmp"); |
| Arg.Imm = Symbol("Imm"); |
| Arg.BigImm = Symbol("BigImm"); |
| Arg.BitImm = Symbol("BitImm"); |
| Arg.BitImm64 = Symbol("BitImm64"); |
| Arg.Addr = Symbol("Addr"); |
| Arg.Stack = Symbol("Stack"); |
| Arg.CallArg = Symbol("CallArg"); |
| Arg.Index = Symbol("Index"); |
| Arg.RelCond = Symbol("RelCond"); |
| Arg.ResCond = Symbol("ResCond"); |
| Arg.DoubleCond = Symbol("DoubleCond"); |
| Arg.Special = Symbol("Special"); |
| Arg.Width = Symbol("Width"); |
| |
| // Arg roles |
| Arg.Use = Symbol("Use"); |
| Arg.ColdUse = Symbol("ColdUse"); |
| Arg.LateUse = Symbol("LateUse"); |
| Arg.LateColdUse = Symbol("LateColdUse"); |
| Arg.Def = Symbol("Def"); |
| Arg.ZDef = Symbol("ZDef"); |
| Arg.UseDef = Symbol("UseDef"); |
| Arg.UseZDef = Symbol("UseZDef"); |
| Arg.EarlyDef = Symbol("EarlyDef"); |
| Arg.Scratch = Symbol("Scratch"); |
| Arg.UseAddr = Symbol("UseAddr"); |
| |