require "config"
require "ast"
require "opt"
def cloopMapType(type)
case type
when :int; ".i()"
when :uint; ".u()"
when :int32; ".i32()"
when :uint32; ".u32()"
when :int64; ".i64()"
when :uint64; ".u64()"
when :int8; ".i8()"
when :uint8; ".u8()"
when :int8Ptr; ".i8p()"
when :voidPtr; ".vp()"
when :nativeFunc; ".nativeFunc()"
when :double; ".d()"
when :bitsAsDouble; ".bitsAsDouble()"
when :bitsAsInt64; ".bitsAsInt64()"
when :opcode; ".opcode()"
else;
raise "Unsupported type"
end
end
class SpecialRegister < NoChildren
def clLValue(type=:int)
clDump
end
def clDump
@name
end
def clValue(type=:int)
@name + cloopMapType(type)
end
end
C_LOOP_SCRATCH_FPR = SpecialRegister.new("d6")
class RegisterID
def clDump
case name
when "t0", "a0", "r0"
"t0"
when "t1", "a1", "r1"
"t1"
when "t2", "a2"
"t2"
when "t3", "a3"
"t3"
when "t4"
"pc"
when "t5"
"t5"
when "csr0"
"pcBase"
when "csr1"
"tagTypeNumber"
when "csr2"
"tagMask"
when "csr3"
"metadataTable"
when "cfr"
"cfr"
when "lr"
"lr"
when "sp"
"sp"
else
raise "Bad register #{name} for C_LOOP at #{codeOriginString}"
end
end
def clLValue(type=:int)
clDump
end
def clValue(type=:int)
clDump + cloopMapType(type)
end
end
class FPRegisterID
def clDump
case name
when "ft0", "fr"
"d0"
when "ft1"
"d1"
when "ft2"
"d2"
when "ft3"
"d3"
when "ft4"
"d4"
when "ft5"
"d5"
else
raise "Bad register #{name} for C_LOOP at #{codeOriginString}"
end
end
def clLValue(type=:int)
clDump
end
def clValue(type=:int)
clDump + cloopMapType(type)
end
end
class Immediate
def clDump
"#{value}"
end
def clLValue(type=:int)
raise "Immediate cannot be used as an LValue"
end
def clValue(type=:int)
valueStr = (value < 0) ? "#{value}" : "0x#{value.to_s(16)}"
case type
when :int8; "int8_t(#{valueStr})"
when :int32; "int32_t(#{valueStr})"
when :int64; "int64_t(#{valueStr})"
when :int; "intptr_t(#{valueStr})"
when :uint8; "uint8_t(#{valueStr})"
when :uint32; "uint32_t(#{valueStr})"
when :uint64; "uint64_t(#{valueStr})"
when :uint; "uintptr_t(#{valueStr})"
else
raise "Not implemented immediate of type: #{type}"
end
end
end
class Address
def clDump
"[#{base.clDump}, #{offset.value}]"
end
def clLValue(type=:int)
clValue(type)
end
def clValue(type=:int)
case type
when :int8; int8MemRef
when :int32; int32MemRef
when :int64; int64MemRef
when :int; intMemRef
when :uint8; uint8MemRef
when :uint32; uint32MemRef
when :uint64; uint64MemRef
when :uint; uintMemRef
when :opcode; opcodeMemRef
when :nativeFunc; nativeFuncMemRef
else
raise "Unexpected Address type: #{type}"
end
end
def pointerExpr
if offset.value == 0
"#{base.clValue(:int8Ptr)}"
elsif offset.value > 0
"#{base.clValue(:int8Ptr)} + #{offset.value}"
else
"#{base.clValue(:int8Ptr)} - #{-offset.value}"
end
end
def int8MemRef
"*CAST<int8_t*>(#{pointerExpr})"
end
def int16MemRef
"*CAST<int16_t*>(#{pointerExpr})"
end
def int32MemRef
"*CAST<int32_t*>(#{pointerExpr})"
end
def int64MemRef
"*CAST<int64_t*>(#{pointerExpr})"
end
def intMemRef
"*CAST<intptr_t*>(#{pointerExpr})"
end
def uint8MemRef
"*CAST<uint8_t*>(#{pointerExpr})"
end
def uint16MemRef
"*CAST<uint16_t*>(#{pointerExpr})"
end
def uint32MemRef
"*CAST<uint32_t*>(#{pointerExpr})"
end
def uint64MemRef
"*CAST<uint64_t*>(#{pointerExpr})"
end
def uintMemRef
"*CAST<uintptr_t*>(#{pointerExpr})"
end
def nativeFuncMemRef
"*CAST<NativeFunction*>(#{pointerExpr})"
end
def opcodeMemRef
"*CAST<Opcode*>(#{pointerExpr})"
end
def dblMemRef
"*CAST<double*>(#{pointerExpr})"
end
end
class BaseIndex
def clDump
"[#{base.clDump}, #{offset.clDump}, #{index.clDump} << #{scaleShift}]"
end
def clLValue(type=:int)
clValue(type)
end
def clValue(type=:int)
case type
when :int8; int8MemRef
when :int32; int32MemRef
when :int64; int64MemRef
when :int; intMemRef
when :uint8; uint8MemRef
when :uint32; uint32MemRef
when :uint64; uint64MemRef
when :uint; uintMemRef
when :opcode; opcodeMemRef
else
raise "Unexpected BaseIndex type: #{type}"
end
end
def pointerExpr
if offset.value == 0
"#{base.clValue(:int8Ptr)} + (#{index.clValue} << #{scaleShift})"
else
"#{base.clValue(:int8Ptr)} + (#{index.clValue} << #{scaleShift}) + #{offset.clValue}"
end
end
def int8MemRef
"*CAST<int8_t*>(#{pointerExpr})"
end
def int16MemRef
"*CAST<int16_t*>(#{pointerExpr})"
end
def int32MemRef
"*CAST<int32_t*>(#{pointerExpr})"
end
def int64MemRef
"*CAST<int64_t*>(#{pointerExpr})"
end
def intMemRef
"*CAST<intptr_t*>(#{pointerExpr})"
end
def uint8MemRef
"*CAST<uint8_t*>(#{pointerExpr})"
end
def uint16MemRef
"*CAST<uint16_t*>(#{pointerExpr})"
end
def uint32MemRef
"*CAST<uint32_t*>(#{pointerExpr})"
end
def uint64MemRef
"*CAST<uint64_t*>(#{pointerExpr})"
end
def uintMemRef
"*CAST<uintptr_t*>(#{pointerExpr})"
end
def opcodeMemRef
"*CAST<Opcode*>(#{pointerExpr})"
end
def dblMemRef
"*CAST<double*>(#{pointerExpr})"
end
end
class AbsoluteAddress
def clDump
"#{codeOriginString}"
end
def clLValue(type=:int)
clValue(type)
end
def clValue
clDump
end
end
class LabelReference
def intMemRef
"*CAST<intptr_t*>(&#{cLabel})"
end
def cloopEmitLea(destination, type)
$asm.putc "#{destination.clLValue(:voidPtr)} = CAST<void*>(&#{cLabel});"
end
end
class Address
def cloopEmitLea(destination, type)
if destination == base
$asm.putc "#{destination.clLValue(:int8Ptr)} += #{offset.clValue(type)};"
else
$asm.putc "#{destination.clLValue(:int8Ptr)} = #{base.clValue(:int8Ptr)} + #{offset.clValue(type)};"
end
end
end
class BaseIndex
def cloopEmitLea(destination, type)
raise "Malformed BaseIndex, offset should be zero at #{codeOriginString}" unless offset.value == 0
$asm.putc "#{destination.clLValue(:int8Ptr)} = #{base.clValue(:int8Ptr)} + (#{index.clValue} << #{scaleShift});"
end
end
class Sequence
def getModifiedListC_LOOP
myList = @list
myList.each {
| node |
unless node.is_a? Instruction or
node.is_a? Label or
node.is_a? LocalLabel or
node.is_a? Skip
raise "Unexpected #{node.inspect} at #{node.codeOrigin}"
end
}
return myList
end
end
def clOperands(operands)
operands.map{|v| v.clDump}.join(", ")
end
def cloopEmitOperation(operands, type, operator)
raise unless type == :int || type == :uint || type == :int32 || type == :uint32 || \
type == :int64 || type == :uint64 || type == :double
if operands.size == 3
op1 = operands[0]
op2 = operands[1]
dst = operands[2]
else
raise unless operands.size == 2
op1 = operands[1]
op2 = operands[0]
dst = operands[1]
end
raise unless not dst.is_a? Immediate
if dst.is_a? RegisterID and (type == :int32 or type == :uint32)
truncationHeader = "(uint32_t)("
truncationFooter = ")"
else
truncationHeader = ""
truncationFooter = ""
end
$asm.putc "#{dst.clLValue(type)} = #{truncationHeader}#{op1.clValue(type)} #{operator} #{op2.clValue(type)}#{truncationFooter};"
end
def cloopEmitShiftOperation(operands, type, operator)
raise unless type == :int || type == :uint || type == :int32 || type == :uint32 || type == :int64 || type == :uint64
if operands.size == 3
op1 = operands[0]
op2 = operands[1]
dst = operands[2]
else
op1 = operands[1]
op2 = operands[0]
dst = operands[1]
end
if dst.is_a? RegisterID and (type == :int32 or type == :uint32)
truncationHeader = "(uint32_t)("
truncationFooter = ")"
else
truncationHeader = ""
truncationFooter = ""
end
$asm.putc "#{dst.clLValue(type)} = #{truncationHeader}#{operands[1].clValue(type)} #{operator} (#{operands[0].clValue(:int)} & 0x1f)#{truncationFooter};"
end
def cloopEmitUnaryOperation(operands, type, operator)
raise unless type == :int || type == :uint || type == :int32 || type == :uint32 || type == :int64 || type == :uint64
raise unless operands.size == 1
raise unless not operands[0].is_a? Immediate
op = operands[0]
dst = operands[0]
if dst.is_a? RegisterID and (type == :int32 or type == :uint32)
truncationHeader = "(uint32_t)("
truncationFooter = ")"
else
truncationHeader = ""
truncationFooter = ""
end
$asm.putc "#{dst.clLValue(type)} = #{truncationHeader}#{operator}#{op.clValue(type)}#{truncationFooter};"
end
def cloopEmitCompareDoubleWithNaNCheckAndBranch(operands, condition)
$asm.putc "if (std::isnan(#{operands[0].clValue(:double)}) || std::isnan(#{operands[1].clValue(:double)})"
$asm.putc " || (#{operands[0].clValue(:double)} #{condition} #{operands[1].clValue(:double)}))"
$asm.putc " goto #{operands[2].cLabel};"
end
def cloopEmitCompareAndSet(operands, type, comparator)
$asm.putc "#{operands[2].clLValue(type)} = (#{operands[0].clValue(type)} #{comparator} #{operands[1].clValue(type)});"
end
def cloopEmitCompareAndBranch(operands, type, comparator)
$asm.putc "if (#{operands[0].clValue(type)} #{comparator} #{operands[1].clValue(type)})"
$asm.putc " goto #{operands[2].cLabel};"
end
def cloopGenerateConditionExpression(operands, type, conditionTest)
op1 = operands[0].clValue(type)
case operands.size
when 2 lhs = op1
when 3 lhs = "(#{op1} & #{operands[1].clValue(type)})"
else
raise "Expected 2 or 3 operands but got #{operands.size} at #{codeOriginString}"
end
"#{lhs} #{conditionTest}"
end
def cloopEmitTestAndBranchIf(operands, type, conditionTest, branchTarget)
conditionExpr = cloopGenerateConditionExpression(operands, type, conditionTest)
$asm.putc "if (#{conditionExpr})"
$asm.putc " goto #{branchTarget};"
end
def cloopEmitTestSet(operands, type, conditionTest)
conditionExpr = cloopGenerateConditionExpression(operands, type, conditionTest)
$asm.putc "#{operands[-1].clLValue} = (#{conditionExpr});"
end
def cloopEmitOpAndBranch(operands, operator, type, conditionTest)
case type
when :int; tempType = "intptr_t"
when :int32; tempType = "int32_t"
when :int64; tempType = "int64_t"
else
raise "Unimplemented type"
end
$asm.putc "{"
$asm.putc " #{tempType} temp = #{operands[1].clValue(type)} #{operator} #{operands[0].clValue(type)};"
$asm.putc " #{operands[1].clLValue(type)} = temp;"
$asm.putc " if (temp #{conditionTest})"
$asm.putc " goto #{operands[2].cLabel};"
$asm.putc "}"
end
def cloopEmitOpAndBranchIfOverflow(operands, operator, type)
case type
when :int32
tempType = "int32_t"
truncationHeader = "(uint32_t)("
truncationFooter = ")"
else
raise "Unimplemented type"
end
$asm.putc "{"
case operator
when "+"; operation = "add"
when "-"; operation = "sub"
when "*"; operation = "multiply"
else
raise "Unimplemented opeartor"
end
$asm.putc " #{tempType} result;"
$asm.putc " bool success = WTF::ArithmeticOperations<#{tempType}, #{tempType}, #{tempType}>::#{operation}(#{operands[1].clValue(type)}, #{operands[0].clValue(type)}, result);"
$asm.putc " #{operands[1].clLValue(type)} = #{truncationHeader}result#{truncationFooter};"
$asm.putc " if (!success)"
$asm.putc " goto #{operands[2].cLabel};"
$asm.putc "}"
end
def cloopEmitCallSlowPath(operands)
$asm.putc "{"
$asm.putc " cloopStack.setCurrentStackPointer(sp.vp());"
$asm.putc " SlowPathReturnType result = #{operands[0].cLabel}(#{operands[1].clDump}, #{operands[2].clDump});"
$asm.putc " decodeResult(result, t0, t1);"
$asm.putc "}"
end
def cloopEmitCallSlowPathVoid(operands)
$asm.putc "cloopStack.setCurrentStackPointer(sp.vp());"
$asm.putc "#{operands[0].cLabel}(#{operands[1].clDump}, #{operands[2].clDump});"
end
class Instruction
def lowerC_LOOP
case opcode
when "addi"
cloopEmitOperation(operands, :int32, "+")
when "addq"
cloopEmitOperation(operands, :int64, "+")
when "addp"
cloopEmitOperation(operands, :int, "+")
when "andi"
cloopEmitOperation(operands, :int32, "&")
when "andq"
cloopEmitOperation(operands, :int64, "&")
when "andp"
cloopEmitOperation(operands, :int, "&")
when "ori"
cloopEmitOperation(operands, :int32, "|")
when "orq"
cloopEmitOperation(operands, :int64, "|")
when "orp"
cloopEmitOperation(operands, :int, "|")
when "xori"
cloopEmitOperation(operands, :int32, "^")
when "xorq"
cloopEmitOperation(operands, :int64, "^")
when "xorp"
cloopEmitOperation(operands, :int, "^")
when "lshifti"
cloopEmitShiftOperation(operands, :int32, "<<")
when "lshiftq"
cloopEmitShiftOperation(operands, :int64, "<<")
when "lshiftp"
cloopEmitShiftOperation(operands, :int, "<<")
when "rshifti"
cloopEmitShiftOperation(operands, :int32, ">>")
when "rshiftq"
cloopEmitShiftOperation(operands, :int64, ">>")
when "rshiftp"
cloopEmitShiftOperation(operands, :int, ">>")
when "urshifti"
cloopEmitShiftOperation(operands, :uint32, ">>")
when "urshiftq"
cloopEmitShiftOperation(operands, :uint64, ">>")
when "urshiftp"
cloopEmitShiftOperation(operands, :uint, ">>")
when "muli"
cloopEmitOperation(operands, :int32, "*")
when "mulq"
cloopEmitOperation(operands, :int64, "*")
when "mulp"
cloopEmitOperation(operands, :int, "*")
when "subi"
cloopEmitOperation(operands, :int32, "-")
when "subq"
cloopEmitOperation(operands, :int64, "-")
when "subp"
cloopEmitOperation(operands, :int, "-")
when "negi"
cloopEmitUnaryOperation(operands, :int32, "-")
when "negq"
cloopEmitUnaryOperation(operands, :int64, "-")
when "negp"
cloopEmitUnaryOperation(operands, :int, "-")
when "noti"
cloopEmitUnaryOperation(operands, :int32, "~")
when "loadi"
$asm.putc "#{operands[1].clLValue(:uint32)} = #{operands[0].uint32MemRef};"
when "loadis"
$asm.putc "#{operands[1].clLValue(:int32)} = #{operands[0].int32MemRef};"
when "loadq"
$asm.putc "#{operands[1].clLValue(:int64)} = #{operands[0].int64MemRef};"
when "loadp"
$asm.putc "#{operands[1].clLValue} = #{operands[0].intMemRef};"
when "storei"
$asm.putc "#{operands[1].int32MemRef} = #{operands[0].clValue(:int32)};"
when "storeq"
$asm.putc "#{operands[1].int64MemRef} = #{operands[0].clValue(:int64)};"
when "storep"
$asm.putc "#{operands[1].intMemRef} = #{operands[0].clValue(:int)};"
when "loadb"
$asm.putc "#{operands[1].clLValue(:int)} = #{operands[0].uint8MemRef};"
when "loadbs"
$asm.putc "#{operands[1].clLValue(:int)} = (uint32_t)(#{operands[0].int8MemRef});"
when "loadbsp"
$asm.putc "#{operands[1].clLValue(:int)} = #{operands[0].int8MemRef};"
when "storeb"
$asm.putc "#{operands[1].uint8MemRef} = #{operands[0].clValue(:int8)};"
when "loadh"
$asm.putc "#{operands[1].clLValue(:int)} = #{operands[0].uint16MemRef};"
when "loadhs"
$asm.putc "#{operands[1].clLValue(:int)} = (uint32_t)(#{operands[0].int16MemRef});"
when "storeh"
$asm.putc "*#{operands[1].uint16MemRef} = #{operands[0].clValue(:int16)};"
when "loadd"
$asm.putc "#{operands[1].clLValue(:double)} = #{operands[0].dblMemRef};"
when "stored"
$asm.putc "#{operands[1].dblMemRef} = #{operands[0].clValue(:double)};"
when "addd"
cloopEmitOperation(operands, :double, "+")
when "divd"
cloopEmitOperation(operands, :double, "/")
when "subd"
cloopEmitOperation(operands, :double, "-")
when "muld"
cloopEmitOperation(operands, :double, "*")
when "ci2d"
$asm.putc "#{operands[1].clLValue(:double)} = (double)#{operands[0].clValue(:int32)}; // ci2d"
when "bdeq"
cloopEmitCompareAndBranch(operands, :double, "==")
when "bdneq"
cloopEmitCompareAndBranch(operands, :double, "!=")
when "bdgt"
cloopEmitCompareAndBranch(operands, :double, ">");
when "bdgteq"
cloopEmitCompareAndBranch(operands, :double, ">=");
when "bdlt"
cloopEmitCompareAndBranch(operands, :double, "<");
when "bdlteq"
cloopEmitCompareAndBranch(operands, :double, "<=");
when "bdequn"
cloopEmitCompareDoubleWithNaNCheckAndBranch(operands, "==")
when "bdnequn"
cloopEmitCompareDoubleWithNaNCheckAndBranch(operands, "!=")
when "bdgtun"
cloopEmitCompareDoubleWithNaNCheckAndBranch(operands, ">")
when "bdgtequn"
cloopEmitCompareDoubleWithNaNCheckAndBranch(operands, ">=")
when "bdltun"
cloopEmitCompareDoubleWithNaNCheckAndBranch(operands, "<")
when "bdltequn"
cloopEmitCompareDoubleWithNaNCheckAndBranch(operands, "<=")
when "td2i"
$asm.putc "#{operands[1].clLValue(:int)} = (uint32_t)(intptr_t)#{operands[0].clValue(:double)}; // td2i"
when "bcd2i" $asm.putc "{ // bcd2i"
$asm.putc " double d = #{operands[0].clValue(:double)};"
$asm.putc " const int32_t asInt32 = int32_t(d);"
$asm.putc " if (asInt32 != d || (!asInt32 && std::signbit(d))) // true for -0.0"
$asm.putc " goto #{operands[2].cLabel};"
$asm.putc " #{operands[1].clLValue} = (uint32_t)asInt32;"
$asm.putc "}"
when "move"
$asm.putc "#{operands[1].clLValue(:int)} = #{operands[0].clValue(:int)};"
when "sxi2q"
$asm.putc "#{operands[1].clLValue(:int64)} = #{operands[0].clValue(:int32)};"
when "zxi2q"
$asm.putc "#{operands[1].clLValue(:uint64)} = #{operands[0].clValue(:uint32)};"
when "nop"
$asm.putc "// nop"
when "bbeq"
cloopEmitCompareAndBranch(operands, :int8, "==")
when "bieq"
cloopEmitCompareAndBranch(operands, :int32, "==")
when "bqeq"
cloopEmitCompareAndBranch(operands, :int64, "==")
when "bpeq"
cloopEmitCompareAndBranch(operands, :int, "==")
when "bbneq"
cloopEmitCompareAndBranch(operands, :int8, "!=")
when "bineq"
cloopEmitCompareAndBranch(operands, :int32, "!=")
when "bqneq"
cloopEmitCompareAndBranch(operands, :int64, "!=")
when "bpneq"
cloopEmitCompareAndBranch(operands, :int, "!=")
when "bba"
cloopEmitCompareAndBranch(operands, :uint8, ">")
when "bia"
cloopEmitCompareAndBranch(operands, :uint32, ">")
when "bqa"
cloopEmitCompareAndBranch(operands, :uint64, ">")
when "bpa"
cloopEmitCompareAndBranch(operands, :uint, ">")
when "bbaeq"
cloopEmitCompareAndBranch(operands, :uint8, ">=")
when "biaeq"
cloopEmitCompareAndBranch(operands, :uint32, ">=")
when "bqaeq"
cloopEmitCompareAndBranch(operands, :uint64, ">=")
when "bpaeq"
cloopEmitCompareAndBranch(operands, :uint, ">=")
when "bbb"
cloopEmitCompareAndBranch(operands, :uint8, "<")
when "bib"
cloopEmitCompareAndBranch(operands, :uint32, "<")
when "bqb"
cloopEmitCompareAndBranch(operands, :uint64, "<")
when "bpb"
cloopEmitCompareAndBranch(operands, :uint, "<")
when "bbbeq"
cloopEmitCompareAndBranch(operands, :uint8, "<=")
when "bibeq"
cloopEmitCompareAndBranch(operands, :uint32, "<=")
when "bqbeq"
cloopEmitCompareAndBranch(operands, :uint64, "<=")
when "bpbeq"
cloopEmitCompareAndBranch(operands, :uint, "<=")
when "bbgt"
cloopEmitCompareAndBranch(operands, :int8, ">")
when "bigt"
cloopEmitCompareAndBranch(operands, :int32, ">")
when "bqgt"
cloopEmitCompareAndBranch(operands, :int64, ">")
when "bpgt"
cloopEmitCompareAndBranch(operands, :int, ">")
when "bbgteq"
cloopEmitCompareAndBranch(operands, :int8, ">=")
when "bigteq"
cloopEmitCompareAndBranch(operands, :int32, ">=")
when "bqgteq"
cloopEmitCompareAndBranch(operands, :int64, ">=")
when "bpgteq"
cloopEmitCompareAndBranch(operands, :int, ">=")
when "bblt"
cloopEmitCompareAndBranch(operands, :int8, "<")
when "bilt"
cloopEmitCompareAndBranch(operands, :int32, "<")
when "bqlt"
cloopEmitCompareAndBranch(operands, :int64, "<")
when "bplt"
cloopEmitCompareAndBranch(operands, :int, "<")
when "bblteq"
cloopEmitCompareAndBranch(operands, :int8, "<=")
when "bilteq"
cloopEmitCompareAndBranch(operands, :int32, "<=")
when "bqlteq"
cloopEmitCompareAndBranch(operands, :int64, "<=")
when "bplteq"
cloopEmitCompareAndBranch(operands, :int, "<=")
when "btbz"
cloopEmitTestAndBranchIf(operands, :int8, "== 0", operands[-1].cLabel)
when "btiz"
cloopEmitTestAndBranchIf(operands, :int32, "== 0", operands[-1].cLabel)
when "btqz"
cloopEmitTestAndBranchIf(operands, :int64, "== 0", operands[-1].cLabel)
when "btpz"
cloopEmitTestAndBranchIf(operands, :int, "== 0", operands[-1].cLabel)
when "btbnz"
cloopEmitTestAndBranchIf(operands, :int8, "!= 0", operands[-1].cLabel)
when "btinz"
cloopEmitTestAndBranchIf(operands, :int32, "!= 0", operands[-1].cLabel)
when "btqnz"
cloopEmitTestAndBranchIf(operands, :int64, "!= 0", operands[-1].cLabel)
when "btpnz"
cloopEmitTestAndBranchIf(operands, :int, "!= 0", operands[-1].cLabel)
when "btbs"
cloopEmitTestAndBranchIf(operands, :int8, "< 0", operands[-1].cLabel)
when "btis"
cloopEmitTestAndBranchIf(operands, :int32, "< 0", operands[-1].cLabel)
when "btqs"
cloopEmitTestAndBranchIf(operands, :int64, "< 0", operands[-1].cLabel)
when "btps"
cloopEmitTestAndBranchIf(operands, :int, "< 0", operands[-1].cLabel)
when "jmp"
if operands[0].is_a? LocalLabelReference or operands[0].is_a? LabelReference
$asm.putc "goto #{operands[0].cLabel};"
else
$asm.putc "opcode = #{operands[0].clValue(:opcode)};"
$asm.putc "DISPATCH_OPCODE();"
end
when "call"
$asm.putc "CRASH(); // generic call instruction not supported by design!"
when "break"
$asm.putc "CRASH(); // break instruction not implemented."
when "ret"
$asm.putc "opcode = lr.opcode();"
$asm.putc "DISPATCH_OPCODE();"
when "cbeq"
cloopEmitCompareAndSet(operands, :uint8, "==")
when "cieq"
cloopEmitCompareAndSet(operands, :uint32, "==")
when "cqeq"
cloopEmitCompareAndSet(operands, :uint64, "==")
when "cpeq"
cloopEmitCompareAndSet(operands, :uint, "==")
when "cbneq"
cloopEmitCompareAndSet(operands, :uint8, "!=")
when "cineq"
cloopEmitCompareAndSet(operands, :uint32, "!=")
when "cqneq"
cloopEmitCompareAndSet(operands, :uint64, "!=")
when "cpneq"
cloopEmitCompareAndSet(operands, :uint, "!=")
when "cba"
cloopEmitCompareAndSet(operands, :uint8, ">")
when "cia"
cloopEmitCompareAndSet(operands, :uint32, ">")
when "cqa"
cloopEmitCompareAndSet(operands, :uint64, ">")
when "cpa"
cloopEmitCompareAndSet(operands, :uint, ">")
when "cbaeq"
cloopEmitCompareAndSet(operands, :uint8, ">=")
when "ciaeq"
cloopEmitCompareAndSet(operands, :uint32, ">=")
when "cqaeq"
cloopEmitCompareAndSet(operands, :uint64, ">=")
when "cpaeq"
cloopEmitCompareAndSet(operands, :uint, ">=")
when "cbb"
cloopEmitCompareAndSet(operands, :uint8, "<")
when "cib"
cloopEmitCompareAndSet(operands, :uint32, "<")
when "cqb"
cloopEmitCompareAndSet(operands, :uint64, "<")
when "cpb"
cloopEmitCompareAndSet(operands, :uint, "<")
when "cbbeq"
cloopEmitCompareAndSet(operands, :uint8, "<=")
when "cibeq"
cloopEmitCompareAndSet(operands, :uint32, "<=")
when "cqbeq"
cloopEmitCompareAndSet(operands, :uint64, "<=")
when "cpbeq"
cloopEmitCompareAndSet(operands, :uint, "<=")
when "cbgt"
cloopEmitCompareAndSet(operands, :int8, ">")
when "cigt"
cloopEmitCompareAndSet(operands, :int32, ">")
when "cqgt"
cloopEmitCompareAndSet(operands, :int64, ">")
when "cpgt"
cloopEmitCompareAndSet(operands, :int, ">")
when "cbgteq"
cloopEmitCompareAndSet(operands, :int8, ">=")
when "cigteq"
cloopEmitCompareAndSet(operands, :int32, ">=")
when "cqgteq"
cloopEmitCompareAndSet(operands, :int64, ">=")
when "cpgteq"
cloopEmitCompareAndSet(operands, :int, ">=")
when "cblt"
cloopEmitCompareAndSet(operands, :int8, "<")
when "cilt"
cloopEmitCompareAndSet(operands, :int32, "<")
when "cqlt"
cloopEmitCompareAndSet(operands, :int64, "<")
when "cplt"
cloopEmitCompareAndSet(operands, :int, "<")
when "cblteq"
cloopEmitCompareAndSet(operands, :int8, "<=")
when "cilteq"
cloopEmitCompareAndSet(operands, :int32, "<=")
when "cqlteq"
cloopEmitCompareAndSet(operands, :int64, "<=")
when "cplteq"
cloopEmitCompareAndSet(operands, :int, "<=")
when "tbs"
cloopEmitTestSet(operands, :int8, "< 0")
when "tis"
cloopEmitTestSet(operands, :int32, "< 0")
when "tqs"
cloopEmitTestSet(operands, :int64, "< 0")
when "tps"
cloopEmitTestSet(operands, :int, "< 0")
when "tbz"
cloopEmitTestSet(operands, :int8, "== 0")
when "tiz"
cloopEmitTestSet(operands, :int32, "== 0")
when "tqz"
cloopEmitTestSet(operands, :int64, "== 0")
when "tpz"
cloopEmitTestSet(operands, :int, "== 0")
when "tbnz"
cloopEmitTestSet(operands, :int8, "!= 0")
when "tinz"
cloopEmitTestSet(operands, :int32, "!= 0")
when "tqnz"
cloopEmitTestSet(operands, :int64, "!= 0")
when "tpnz"
cloopEmitTestSet(operands, :int, "!= 0")
when "cdqi"
$asm.putc "{ // cdqi"
$asm.putc " int64_t temp = t0.i32(); // sign extend the low 32bit"
$asm.putc " t0 = (uint32_t)temp; // low word"
$asm.putc " t1 = (uint32_t)(temp >> 32); // high word"
$asm.putc "}"
when "idivi"
$asm.putc "{ // idivi"
$asm.putc " int64_t dividend = (int64_t(t1.u32()) << 32) | t0.u32();"
$asm.putc " int64_t divisor = #{operands[0].clValue(:int)};"
$asm.putc " t1 = (uint32_t)(dividend % divisor); // remainder"
$asm.putc " t0 = (uint32_t)(dividend / divisor); // quotient"
$asm.putc "}"
when "fii2d"
$asm.putc "#{operands[2].clLValue(:double)} = ints2Double(#{operands[0].clValue(:uint32)}, #{operands[1].clValue(:uint32)}); // fii2d"
when "fd2ii"
$asm.putc "double2Ints(#{operands[0].clValue(:double)}, #{operands[1].clDump}, #{operands[2].clDump}); // fd2ii"
when "fq2d"
$asm.putc "#{operands[1].clLValue(:double)} = #{operands[0].clValue(:bitsAsDouble)}; // fq2d"
when "fd2q"
$asm.putc "#{operands[1].clLValue(:int64)} = #{operands[0].clValue(:bitsAsInt64)}; // fd2q"
when "leai"
operands[0].cloopEmitLea(operands[1], :int32)
when "leap"
operands[0].cloopEmitLea(operands[1], :int)
when "baddio"
cloopEmitOpAndBranchIfOverflow(operands, "+", :int32)
when "bsubio"
cloopEmitOpAndBranchIfOverflow(operands, "-", :int32)
when "bmulio"
cloopEmitOpAndBranchIfOverflow(operands, "*", :int32)
when "baddis"
cloopEmitOpAndBranch(operands, "+", :int32, "< 0")
when "baddiz"
cloopEmitOpAndBranch(operands, "+", :int32, "== 0")
when "baddinz"
cloopEmitOpAndBranch(operands, "+", :int32, "!= 0")
when "baddqs"
cloopEmitOpAndBranch(operands, "+", :int64, "< 0")
when "baddqz"
cloopEmitOpAndBranch(operands, "+", :int64, "== 0")
when "baddqnz"
cloopEmitOpAndBranch(operands, "+", :int64, "!= 0")
when "baddps"
cloopEmitOpAndBranch(operands, "+", :int, "< 0")
when "baddpz"
cloopEmitOpAndBranch(operands, "+", :int, "== 0")
when "baddpnz"
cloopEmitOpAndBranch(operands, "+", :int, "!= 0")
when "bsubis"
cloopEmitOpAndBranch(operands, "-", :int32, "< 0")
when "bsubiz"
cloopEmitOpAndBranch(operands, "-", :int32, "== 0")
when "bsubinz"
cloopEmitOpAndBranch(operands, "-", :int32, "!= 0")
when "borris"
cloopEmitOpAndBranch(operands, "|", :int32, "< 0")
when "borriz"
cloopEmitOpAndBranch(operands, "|", :int32, "== 0")
when "borrinz"
cloopEmitOpAndBranch(operands, "|", :int32, "!= 0")
when "memfence"
when "push"
operands.each {
| op |
$asm.putc "PUSH(#{op.clDump});"
}
when "pop"
operands.each {
| op |
$asm.putc "POP(#{op.clDump});"
}
when "cloopCrash"
$asm.putc "CRASH();"
when "cloopCallJSFunction"
uid = $asm.newUID
$asm.putc "lr = getOpcode(llint_cloop_did_return_from_js_#{uid});"
$asm.putc "opcode = #{operands[0].clValue(:opcode)};"
$asm.putc "DISPATCH_OPCODE();"
$asm.putsLabel("llint_cloop_did_return_from_js_#{uid}", false)
when "cloopCallNative"
$asm.putc "cloopStack.setCurrentStackPointer(sp.vp());"
$asm.putc "nativeFunc = #{operands[0].clValue(:nativeFunc)};"
$asm.putc "functionReturnValue = JSValue::decode(nativeFunc(t0.execState()));"
$asm.putc "#if USE(JSVALUE32_64)"
$asm.putc " t1 = functionReturnValue.tag();"
$asm.putc " t0 = functionReturnValue.payload();"
$asm.putc "#else // USE_JSVALUE64)"
$asm.putc " t0 = JSValue::encode(functionReturnValue);"
$asm.putc "#endif // USE_JSVALUE64)"
when "cloopCallSlowPath"
cloopEmitCallSlowPath(operands)
when "cloopCallSlowPathVoid"
cloopEmitCallSlowPathVoid(operands)
when "cloopDo"
$asm.putc "#{annotation}"
else
lowerDefault
end
end
def recordMetaDataC_LOOP
$asm.codeOrigin codeOriginString if $enableCodeOriginComments
$asm.annotation annotation if $enableInstrAnnotations && (opcode != "cloopDo")
$asm.debugAnnotation codeOrigin.debugDirective if $enableDebugAnnotations
end
end