require 'config'
require 'ast'
require 'opt'
def riscLowerSimpleBranchOps(list)
newList = []
list.each {
| node |
if node.is_a? Instruction
annotation = node.annotation
case node.opcode
when /^b(addi|subi|ori|addp)/
op = $1
branch = "b" + $~.post_match
case op
when "addi"
op = "addis"
when "addp"
op = "addps"
when "subi"
op = "subis"
when "ori"
op = "oris"
end
newList << Instruction.new(node.codeOrigin, op, node.operands[0..-2], annotation)
newList << Instruction.new(node.codeOrigin, branch, [node.operands[-1]])
when 'bmulis', 'bmulz', 'bmulnz'
condition = $~.post_match
newList << Instruction.new(node.codeOrigin, "muli", node.operands[0..-2], annotation)
newList << Instruction.new(node.codeOrigin, "bti" + condition, [node.operands[-2], node.operands[-1]])
else
newList << node
end
else
newList << node
end
}
newList
end
def riscLowerHardBranchOps(list)
newList = []
list.each {
| node |
if node.is_a? Instruction and node.opcode == "bmulio"
tmp1 = Tmp.new(node.codeOrigin, :gpr)
tmp2 = Tmp.new(node.codeOrigin, :gpr)
newList << Instruction.new(node.codeOrigin, "smulli", [node.operands[0], node.operands[1], node.operands[1], tmp1], node.annotation)
newList << Instruction.new(node.codeOrigin, "rshifti", [node.operands[-2], Immediate.new(node.codeOrigin, 31), tmp2])
newList << Instruction.new(node.codeOrigin, "bineq", [tmp1, tmp2, node.operands[-1]])
else
newList << node
end
}
newList
end
def riscSanitizeShift(operand, list)
return operand if operand.immediate?
tmp = Tmp.new(operand.codeOrigin, :gpr)
list << Instruction.new(operand.codeOrigin, "andi", [operand, Immediate.new(operand.codeOrigin, 31), tmp])
tmp
end
def riscLowerShiftOps(list)
newList = []
list.each {
| node |
if node.is_a? Instruction
case node.opcode
when "lshifti", "rshifti", "urshifti", "lshiftp", "rshiftp", "urshiftp"
if node.operands.size == 2
newList << Instruction.new(node.codeOrigin, node.opcode, [riscSanitizeShift(node.operands[0], newList), node.operands[1]], node.annotation)
else
newList << Instruction.new(node.codeOrigin, node.opcode, [node.operands[0], riscSanitizeShift(node.operands[1], newList), node.operands[2]], node.annotation)
raise "Wrong number of operands for shift at #{node.codeOriginString}" unless node.operands.size == 3
end
else
newList << node
end
else
newList << node
end
}
newList
end
class Node
def riscLowerMalformedAddressesRecurse(list, topLevelNode, &block)
mapChildren {
| subNode |
subNode.riscLowerMalformedAddressesRecurse(list, topLevelNode, &block)
}
end
end
class Address
def riscLowerMalformedAddressesRecurse(list, node, &block)
return self if yield node, self
tmp = Tmp.new(codeOrigin, :gpr)
list << Instruction.new(codeOrigin, "move", [offset, tmp])
list << Instruction.new(codeOrigin, "addp", [base, tmp])
Address.new(codeOrigin, tmp, Immediate.new(codeOrigin, 0))
end
end
class BaseIndex
def riscLowerMalformedAddressesRecurse(list, node, &block)
return self if yield node, self
tmp = Tmp.new(codeOrigin, :gpr)
list << Instruction.new(codeOrigin, "leap", [BaseIndex.new(codeOrigin, base, index, scale, Immediate.new(codeOrigin, 0)), tmp])
Address.new(codeOrigin, tmp, offset).riscLowerMalformedAddressesRecurse(list, node, &block)
end
end
class AbsoluteAddress
def riscLowerMalformedAddressesRecurse(list, node, &block)
return self if yield node, self
tmp = Tmp.new(codeOrigin, :gpr)
list << Instruction.new(codeOrigin, "move", [address, tmp])
Address.new(codeOrigin, tmp, Immediate.new(codeOrigin, 0))
end
end
def riscLowerMalformedAddresses(list, &block)
newList = []
list.each {
| node |
newList << node.riscLowerMalformedAddressesRecurse(newList, node, &block)
}
newList
end
class Node
def riscDoubleAddress(list)
self
end
end
class BaseIndex
def riscDoubleAddress(list)
tmp = Tmp.new(codeOrigin, :gpr)
list << Instruction.new(codeOrigin, "leap", [self, tmp])
Address.new(codeOrigin, tmp, Immediate.new(codeOrigin, 0))
end
end
def riscLowerMalformedAddressesDouble(list)
newList = []
list.each {
| node |
if node.is_a? Instruction
case node.opcode
when "loadd"
newList << Instruction.new(node.codeOrigin, "loadd", [node.operands[0].riscDoubleAddress(newList), node.operands[1]], node.annotation)
when "stored"
newList << Instruction.new(node.codeOrigin, "stored", [node.operands[0], node.operands[1].riscDoubleAddress(newList)], node.annotation)
else
newList << node
end
else
newList << node
end
}
newList
end
def riscLowerMisplacedImmediates(list, opcodeList)
newList = []
list.each {
| node |
if node.is_a? Instruction
if opcodeList.include? node.opcode
operands = node.operands
newOperands = []
operands.each {
| operand |
if operand.is_a? Immediate
tmp = Tmp.new(operand.codeOrigin, :gpr)
newList << Instruction.new(operand.codeOrigin, "move", [operand, tmp])
newOperands << tmp
else
newOperands << operand
end
}
newList << Instruction.new(node.codeOrigin, node.opcode, newOperands, node.annotation)
else
newList << node
end
else
newList << node
end
}
newList
end
class Node
def riscLowerMalformedImmediatesRecurse(list, validImmediates)
mapChildren {
| node |
node.riscLowerMalformedImmediatesRecurse(list, validImmediates)
}
end
end
class Address
def riscLowerMalformedImmediatesRecurse(list, validImmediates)
self
end
end
class BaseIndex
def riscLowerMalformedImmediatesRecurse(list, validImmediates)
self
end
end
class AbsoluteAddress
def riscLowerMalformedImmediatesRecurse(list, validImmediates)
self
end
end
class Immediate
def riscLowerMalformedImmediatesRecurse(list, validImmediates)
unless validImmediates.include? value
tmp = Tmp.new(codeOrigin, :gpr)
list << Instruction.new(codeOrigin, "move", [self, tmp])
tmp
else
self
end
end
end
def riscLowerMalformedImmediates(list, validImmediates)
newList = []
list.each {
| node |
if node.is_a? Instruction
annotation = node.annotation
case node.opcode
when "move"
newList << node
when "addi", "addp", "addq", "addis", "subi", "subp", "subq", "subis"
if node.operands[0].is_a? Immediate and
(not validImmediates.include? node.operands[0].value) and
validImmediates.include? -node.operands[0].value
node.operands.size == 2
if node.opcode =~ /add/
newOpcode = "sub" + $~.post_match
else
newOpcode = "add" + $~.post_match
end
newList << Instruction.new(node.codeOrigin, newOpcode,
[Immediate.new(node.codeOrigin, -node.operands[0].value)] + node.operands[1..-1],
annotation)
else
newList << node.riscLowerMalformedImmediatesRecurse(newList, validImmediates)
end
when "muli", "mulp", "mulq"
if node.operands[0].is_a? Immediate
tmp = Tmp.new(codeOrigin, :gpr)
newList << Instruction.new(node.codeOrigin, "move", [node.operands[0], tmp], annotation)
newList << Instruction.new(node.codeOrigin, node.opcode, [tmp] + node.operands[1..-1])
else
newList << node.riscLowerMalformedImmediatesRecurse(newList, validImmediates)
end
else
newList << node.riscLowerMalformedImmediatesRecurse(newList, validImmediates)
end
else
newList << node
end
}
newList
end
def riscAsRegister(preList, postList, operand, suffix, needStore)
return operand unless operand.address?
tmp = Tmp.new(operand.codeOrigin, if suffix == "d" then :fpr else :gpr end)
preList << Instruction.new(operand.codeOrigin, "load" + suffix, [operand, tmp])
if needStore
postList << Instruction.new(operand.codeOrigin, "store" + suffix, [tmp, operand])
end
tmp
end
def riscAsRegisters(preList, postList, operands, suffix)
newOperands = []
operands.each_with_index {
| operand, index |
newOperands << riscAsRegister(preList, postList, operand, suffix, index == operands.size - 1)
}
newOperands
end
def riscLowerMisplacedAddresses(list)
newList = []
list.each {
| node |
if node.is_a? Instruction
postInstructions = []
annotation = node.annotation
case node.opcode
when "addi", "addis", "andi", "lshifti", "muli", "negi", "noti", "ori", "oris",
"rshifti", "urshifti", "subi", "subis", "xori", /^bi/, /^bti/, /^ci/, /^ti/
newList << Instruction.new(node.codeOrigin,
node.opcode,
riscAsRegisters(newList, postInstructions, node.operands, "i"),
annotation)
when "addp", "andp", "lshiftp", "mulp", "negp", "orp", "rshiftp", "urshiftp",
"subp", "xorp", /^bp/, /^btp/, /^cp/
newList << Instruction.new(node.codeOrigin,
node.opcode,
riscAsRegisters(newList, postInstructions, node.operands, "p"),
annotation)
when "addq", "andq", "lshiftq", "mulq", "negq", "orq", "rshiftq", "urshiftq",
"subq", "xorq", /^bq/, /^btq/, /^cq/
newList << Instruction.new(node.codeOrigin,
node.opcode,
riscAsRegisters(newList, postInstructions, node.operands, "q"),
annotation)
when "bbeq", "bbneq", "bba", "bbaeq", "bbb", "bbbeq", "btbz", "btbnz", "tbz", "tbnz",
"cbeq", "cbneq", "cba", "cbaeq", "cbb", "cbbeq"
newList << Instruction.new(node.codeOrigin,
node.opcode,
riscAsRegisters(newList, postInstructions, node.operands, "b"),
annotation)
when "bbgt", "bbgteq", "bblt", "bblteq", "btbs", "tbs", "cbgt", "cbgteq", "cblt", "cblteq"
newList << Instruction.new(node.codeOrigin,
node.opcode,
riscAsRegisters(newList, postInstructions, node.operands, "bs"),
annotation)
when "addd", "divd", "subd", "muld", "sqrtd", /^bd/
newList << Instruction.new(node.codeOrigin,
node.opcode,
riscAsRegisters(newList, postInstructions, node.operands, "d"),
annotation)
when "jmp", "call"
newList << Instruction.new(node.codeOrigin,
node.opcode,
[riscAsRegister(newList, postInstructions, node.operands[0], "p", false)],
annotation)
else
newList << node
end
newList += postInstructions
else
newList << node
end
}
newList
end
def riscLowerRegisterReuse(list)
newList = []
list.each {
| node |
if node.is_a? Instruction
annotation = node.annotation
case node.opcode
when "cieq", "cineq", "cia", "ciaeq", "cib", "cibeq", "cigt", "cigteq", "cilt", "cilteq",
"cpeq", "cpneq", "cpa", "cpaeq", "cpb", "cpbeq", "cpgt", "cpgteq", "cplt", "cplteq",
"tis", "tiz", "tinz", "tbs", "tbz", "tbnz", "tps", "tpz", "tpnz", "cbeq", "cbneq",
"cba", "cbaeq", "cbb", "cbbeq", "cbgt", "cbgteq", "cblt", "cblteq"
if node.operands.size == 2
if node.operands[0] == node.operands[1]
tmp = Tmp.new(node.codeOrigin, :gpr)
newList << Instruction.new(node.codeOrigin, "move", [node.operands[0], tmp], annotation)
newList << Instruction.new(node.codeOrigin, node.opcode, [tmp, node.operands[1]])
else
newList << node
end
else
raise "Wrong number of arguments at #{node.codeOriginString}" unless node.operands.size == 3
if node.operands[0] == node.operands[2]
tmp = Tmp.new(node.codeOrigin, :gpr)
newList << Instruction.new(node.codeOrigin, "move", [node.operands[0], tmp], annotation)
newList << Instruction.new(node.codeOrigin, node.opcode, [tmp, node.operands[1], node.operands[2]])
elsif node.operands[1] == node.operands[2]
tmp = Tmp.new(node.codeOrigin, :gpr)
newList << Instruction.new(node.codeOrigin, "move", [node.operands[1], tmp], annotation)
newList << Instruction.new(node.codeOrigin, node.opcode, [node.operands[0], tmp, node.operands[2]])
else
newList << node
end
end
else
newList << node
end
else
newList << node
end
}
newList
end
def riscLowerNot(list)
newList = []
list.each {
| node |
if node.is_a? Instruction
case node.opcode
when "noti", "notp"
raise "Wrong nubmer of operands at #{node.codeOriginString}" unless node.operands.size == 1
suffix = node.opcode[-1..-1]
newList << Instruction.new(node.codeOrigin, "xor" + suffix,
[Immediate.new(node.codeOrigin, -1), node.operands[0]])
else
newList << node
end
else
newList << node
end
}
return newList
end
def riscLowerHardBranchOps64(list)
newList = []
list.each {
| node |
if node.is_a? Instruction and node.opcode == "bmulio"
tmp1 = Tmp.new(node.codeOrigin, :gpr)
tmp2 = Tmp.new(node.codeOrigin, :gpr)
newList << Instruction.new(node.codeOrigin, "smulli", [node.operands[0], node.operands[1], node.operands[1]])
newList << Instruction.new(node.codeOrigin, "rshiftp", [node.operands[1], Immediate.new(node.codeOrigin, 32), tmp1])
newList << Instruction.new(node.codeOrigin, "rshifti", [node.operands[1], Immediate.new(node.codeOrigin, 31), tmp2])
newList << Instruction.new(node.codeOrigin, "zxi2p", [node.operands[1], node.operands[1]])
newList << Instruction.new(node.codeOrigin, "bineq", [tmp1, tmp2, node.operands[2]])
else
newList << node
end
}
newList
end
def riscLowerTest(list)
def emit(newList, andOpcode, branchOpcode, node)
if node.operands.size == 2
newList << Instruction.new(node.codeOrigin, branchOpcode, [node.operands[0], Immediate.new(node.codeOrigin, 0), node.operands[1]])
return
end
raise "Incorrect number of operands at #{codeOriginString}" unless node.operands.size == 3
if node.operands[0].immediate? and node.operands[0].value == -1
newList << Instruction.new(node.codeOrigin, branchOpcode, [node.operands[1], Immediate.new(node.codeOrigin, 0), node.operands[2]])
return
end
if node.operands[1].immediate? and node.operands[1].value == -1
newList << Instruction.new(node.codeOrigin, branchOpcode, [node.operands[0], Immediate.new(node.codeOrigin, 0), node.operands[2]])
return
end
tmp = Tmp.new(node.codeOrigin, :gpr)
newList << Instruction.new(node.codeOrigin, andOpcode, [node.operands[0], node.operands[1], tmp])
newList << Instruction.new(node.codeOrigin, branchOpcode, [tmp, Immediate.new(node.codeOrigin, 0), node.operands[2]])
end
newList = []
list.each {
| node |
if node.is_a? Instruction
case node.opcode
when "btis"
emit(newList, "andi", "bilt", node)
when "btiz"
emit(newList, "andi", "bieq", node)
when "btinz"
emit(newList, "andi", "bineq", node)
when "btps"
emit(newList, "andp", "bplt", node)
when "btpz"
emit(newList, "andp", "bpeq", node)
when "btpnz"
emit(newList, "andp", "bpneq", node)
when "btqs"
emit(newList, "andq", "bqlt", node)
when "btqz"
emit(newList, "andq", "bqeq", node)
when "btqnz"
emit(newList, "andq", "bqneq", node)
when "btbs"
emit(newList, "andi", "bblt", node)
when "btbz"
emit(newList, "andi", "bbeq", node)
when "btbnz"
emit(newList, "andi", "bbneq", node)
when "tis"
emit(newList, "andi", "cilt", node)
when "tiz"
emit(newList, "andi", "cieq", node)
when "tinz"
emit(newList, "andi", "cineq", node)
when "tps"
emit(newList, "andp", "cplt", node)
when "tpz"
emit(newList, "andp", "cpeq", node)
when "tpnz"
emit(newList, "andp", "cpneq", node)
when "tqs"
emit(newList, "andq", "cqlt", node)
when "tqz"
emit(newList, "andq", "cqeq", node)
when "tqnz"
emit(newList, "andq", "cqneq", node)
when "tbs"
emit(newList, "andi", "cblt", node)
when "tbz"
emit(newList, "andi", "cbeq", node)
when "tbnz"
emit(newList, "andi", "cbneq", node)
else
newList << node
end
else
newList << node
end
}
return newList
end