/*
* Copyright (c) 2016, Oracle and/or its affiliates.
*
* 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.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE
* COPYRIGHT HOLDER 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.
*/
package com.oracle.truffle.llvm.asm.amd64;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import com.oracle.truffle.api.frame.FrameDescriptor;
import com.oracle.truffle.api.frame.FrameSlot;
import com.oracle.truffle.api.frame.FrameSlotKind;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64AddNodeFactory.LLVMAMD64AddbNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64AddNodeFactory.LLVMAMD64AddlNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64AddNodeFactory.LLVMAMD64AddqNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64AddNodeFactory.LLVMAMD64AddwNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64AndNodeFactory.LLVMAMD64AndbNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64AndNodeFactory.LLVMAMD64AndlNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64AndNodeFactory.LLVMAMD64AndqNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64AndNodeFactory.LLVMAMD64AndwNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64DecNodeFactory.LLVMAMD64DecbNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64DecNodeFactory.LLVMAMD64DeclNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64DecNodeFactory.LLVMAMD64DecqNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64DecNodeFactory.LLVMAMD64DecwNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64IdivNodeFactory.LLVMAMD64IdivbNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64IdivNodeFactory.LLVMAMD64IdivlNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64IdivNodeFactory.LLVMAMD64IdivqNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64IdivNodeFactory.LLVMAMD64IdivwNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64ImmNodeFactory.LLVMAMD64I16NodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64ImmNodeFactory.LLVMAMD64I32NodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64ImmNodeFactory.LLVMAMD64I64NodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64ImmNodeFactory.LLVMAMD64I8NodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64ImulNodeFactory.LLVMAMD64ImulbNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64ImulNodeFactory.LLVMAMD64ImullNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64ImulNodeFactory.LLVMAMD64ImulqNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64ImulNodeFactory.LLVMAMD64ImulwNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64IncNodeFactory.LLVMAMD64IncbNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64IncNodeFactory.LLVMAMD64InclNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64IncNodeFactory.LLVMAMD64IncqNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64IncNodeFactory.LLVMAMD64IncwNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64MulNodeFactory.LLVMAMD64MulbNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64MulNodeFactory.LLVMAMD64MullNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64MulNodeFactory.LLVMAMD64MulqNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64MulNodeFactory.LLVMAMD64MulwNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64NegNodeFactory.LLVMAMD64NegbNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64NegNodeFactory.LLVMAMD64NeglNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64NegNodeFactory.LLVMAMD64NegqNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64NegNodeFactory.LLVMAMD64NegwNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64NotNodeFactory.LLVMAMD64NotbNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64NotNodeFactory.LLVMAMD64NotlNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64NotNodeFactory.LLVMAMD64NotqNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64NotNodeFactory.LLVMAMD64NotwNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64OrNodeFactory.LLVMAMD64OrbNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64OrNodeFactory.LLVMAMD64OrlNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64OrNodeFactory.LLVMAMD64OrqNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64OrNodeFactory.LLVMAMD64OrwNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64RdtscNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64SalNodeFactory.LLVMAMD64SalbNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64SalNodeFactory.LLVMAMD64SallNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64SalNodeFactory.LLVMAMD64SalqNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64SalNodeFactory.LLVMAMD64SalwNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64SarNodeFactory.LLVMAMD64SarbNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64SarNodeFactory.LLVMAMD64SarlNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64SarNodeFactory.LLVMAMD64SarqNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64SarNodeFactory.LLVMAMD64SarwNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64ShlNodeFactory.LLVMAMD64ShlbNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64ShlNodeFactory.LLVMAMD64ShllNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64ShlNodeFactory.LLVMAMD64ShlqNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64ShlNodeFactory.LLVMAMD64ShlwNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64ShrNodeFactory.LLVMAMD64ShrbNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64ShrNodeFactory.LLVMAMD64ShrlNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64ShrNodeFactory.LLVMAMD64ShrqNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64ShrNodeFactory.LLVMAMD64ShrwNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64SubNodeFactory.LLVMAMD64SubbNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64SubNodeFactory.LLVMAMD64SublNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64SubNodeFactory.LLVMAMD64SubqNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64SubNodeFactory.LLVMAMD64SubwNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64XorNodeFactory.LLVMAMD64XorbNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64XorNodeFactory.LLVMAMD64XorlNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64XorNodeFactory.LLVMAMD64XorqNodeGen;
import com.oracle.truffle.llvm.nodes.asm.LLVMAMD64XorNodeFactory.LLVMAMD64XorwNodeGen;
import com.oracle.truffle.llvm.nodes.asm.support.LLVMAMD64ToRegisterNodeFactory.LLVMI16ToR64NodeGen;
import com.oracle.truffle.llvm.nodes.asm.support.LLVMAMD64ToRegisterNodeFactory.LLVMI32ToR64NodeGen;
import com.oracle.truffle.llvm.nodes.asm.support.LLVMAMD64ToRegisterNodeFactory.LLVMI8ToR64NodeGen;
import com.oracle.truffle.llvm.nodes.asm.support.LLVMAMD64WriteRegisterNode;
import com.oracle.truffle.llvm.nodes.asm.support.LLVMAMD64WriteRegisterNode.LLVMAMD64WriteI16RegisterNode;
import com.oracle.truffle.llvm.nodes.asm.support.LLVMAMD64WriteRegisterNode.LLVMAMD64WriteI32RegisterNode;
import com.oracle.truffle.llvm.nodes.asm.support.LLVMAMD64WriteRegisterNode.LLVMAMD64WriteI64RegisterNode;
import com.oracle.truffle.llvm.nodes.base.LLVMStructWriteNode;
import com.oracle.truffle.llvm.nodes.base.LLVMStructWriteNodeFactory.LLVMPrimitiveStructWriteNodeGen;
import com.oracle.truffle.llvm.nodes.cast.LLVMToI16NodeFactory.LLVMToI16NoZeroExtNodeGen;
import com.oracle.truffle.llvm.nodes.cast.LLVMToI32NodeGen.LLVMToI32NoZeroExtNodeGen;
import com.oracle.truffle.llvm.nodes.cast.LLVMToI64NodeGen.LLVMToI64NoZeroExtNodeGen;
import com.oracle.truffle.llvm.nodes.cast.LLVMToI8NodeGen.LLVMToI8NoZeroExtNodeGen;
import com.oracle.truffle.llvm.nodes.func.LLVMArgNodeGen;
import com.oracle.truffle.llvm.nodes.func.LLVMInlineAssemblyRootNode;
import com.oracle.truffle.llvm.nodes.memory.LLVMAllocInstruction.LLVMAllocaConstInstruction;
import com.oracle.truffle.llvm.nodes.memory.LLVMStoreNodeFactory.LLVMI16StoreNodeGen;
import com.oracle.truffle.llvm.nodes.memory.LLVMStoreNodeFactory.LLVMI32StoreNodeGen;
import com.oracle.truffle.llvm.nodes.memory.LLVMStoreNodeFactory.LLVMI64StoreNodeGen;
import com.oracle.truffle.llvm.nodes.memory.LLVMStoreNodeFactory.LLVMI8StoreNodeGen;
import com.oracle.truffle.llvm.nodes.memory.load.LLVMI16LoadNodeGen;
import com.oracle.truffle.llvm.nodes.memory.load.LLVMI32LoadNodeGen;
import com.oracle.truffle.llvm.nodes.memory.load.LLVMI64LoadNodeGen;
import com.oracle.truffle.llvm.nodes.memory.load.LLVMI8LoadNodeGen;
import com.oracle.truffle.llvm.nodes.others.LLVMUnsupportedInlineAssemblerNode;
import com.oracle.truffle.llvm.nodes.others.LLVMUnsupportedInlineAssemblerNode.LLVMI32UnsupportedInlineAssemblerNode;
import com.oracle.truffle.llvm.nodes.vars.LLVMReadNodeFactory.LLVMAddressReadNodeGen;
import com.oracle.truffle.llvm.nodes.vars.LLVMReadNodeFactory.LLVMDoubleReadNodeGen;
import com.oracle.truffle.llvm.nodes.vars.LLVMReadNodeFactory.LLVMFloatReadNodeGen;
import com.oracle.truffle.llvm.nodes.vars.LLVMReadNodeFactory.LLVMI16ReadNodeGen;
import com.oracle.truffle.llvm.nodes.vars.LLVMReadNodeFactory.LLVMI32ReadNodeGen;
import com.oracle.truffle.llvm.nodes.vars.LLVMReadNodeFactory.LLVMI64ReadNodeGen;
import com.oracle.truffle.llvm.nodes.vars.LLVMReadNodeFactory.LLVMI8ReadNodeGen;
import com.oracle.truffle.llvm.nodes.vars.LLVMWriteNode.LLVMWriteAddressNode;
import com.oracle.truffle.llvm.nodes.vars.LLVMWriteNodeFactory.LLVMWriteAddressNodeGen;
import com.oracle.truffle.llvm.nodes.vars.LLVMWriteNodeFactory.LLVMWriteDoubleNodeGen;
import com.oracle.truffle.llvm.nodes.vars.LLVMWriteNodeFactory.LLVMWriteFloatNodeGen;
import com.oracle.truffle.llvm.nodes.vars.LLVMWriteNodeFactory.LLVMWriteI16NodeGen;
import com.oracle.truffle.llvm.nodes.vars.LLVMWriteNodeFactory.LLVMWriteI32NodeGen;
import com.oracle.truffle.llvm.nodes.vars.LLVMWriteNodeFactory.LLVMWriteI64NodeGen;
import com.oracle.truffle.llvm.nodes.vars.LLVMWriteNodeFactory.LLVMWriteI8NodeGen;
import com.oracle.truffle.llvm.nodes.vars.StructLiteralNode;
import com.oracle.truffle.llvm.runtime.nodes.api.LLVMExpressionNode;
import com.oracle.truffle.llvm.runtime.types.PointerType;
import com.oracle.truffle.llvm.runtime.types.PrimitiveType;
import com.oracle.truffle.llvm.runtime.types.PrimitiveType.PrimitiveKind;
import com.oracle.truffle.llvm.runtime.types.StructureType;
import com.oracle.truffle.llvm.runtime.types.Type;
import com.oracle.truffle.llvm.runtime.types.VoidType;
class AsmFactory {
private FrameDescriptor frameDescriptor;
private List<LLVMExpressionNode> statements;
private List<LLVMExpressionNode> arguments;
private List<String> registers;
private LLVMExpressionNode[] args;
private LLVMExpressionNode result;
private List<Argument> argInfo;
private String asmFlags;
private Type[] argTypes;
private Type retType;
AsmFactory(LLVMExpressionNode[] args, Type[] argTypes, String asmFlags, Type retType) {
this.args = args;
this.argTypes = argTypes;
this.asmFlags = asmFlags;
this.frameDescriptor = new FrameDescriptor();
this.statements = new ArrayList<>();
this.arguments = new ArrayList<>();
this.registers = new ArrayList<>();
this.retType = retType;
parseArguments();
}
private class Argument {
private final boolean input;
private final boolean output;
private final boolean memory;
private final Type type;
private final int index;
private final int inIndex;
private final int outIndex;
private final String source;
private final String register;
Argument(boolean input, boolean output, boolean memory, Type type, int index, int inIndex, int outIndex, String source, String register) {
this.input = input;
this.output = output;
this.memory = memory;
this.type = type;
this.index = index;
this.inIndex = inIndex;
this.outIndex = outIndex;
this.source = source;
this.register = register;
}
public boolean isInput() {
return input;
}
public boolean isOutput() {
return output;
}
public boolean isMemory() {
return memory;
}
public Type getType() {
return type;
}
public int getIndex() {
return index;
}
public int getInIndex() {
assert isInput();
return inIndex;
}
public int getOutIndex() {
assert isOutput();
return outIndex;
}
public String getRegister() {
assert isRegister();
return register;
}
public boolean isRegister() {
return register != null;
}
public LLVMExpressionNode getAddress() {
assert isMemory();
if (output) {
return LLVMArgNodeGen.create(outIndex);
} else {
throw new IllegalStateException();
}
}
@Override
public String toString() {
return String.format("Argument[IDX=%d,I=%s,O=%s,M=%s,T=%s,S=%s]", index, input, output, memory, type, source);
}
}
private void parseArguments() {
argInfo = new ArrayList<>();
String[] tokens = asmFlags.substring(1, asmFlags.length() - 1).split(",");
int index = 0;
LLVMAllocaConstInstruction alloca = null;
if (retType instanceof StructureType) { // multiple out values
assert args[0] instanceof LLVMAllocaConstInstruction;
alloca = (LLVMAllocaConstInstruction) args[0];
index++;
}
int outIndex = 0;
for (String token : tokens) {
boolean isTilde = false;
boolean isInput = true;
boolean isOutput = false;
boolean isMemory = false;
String source = null;
String registerName = null;
int i;
for (i = 0; i < token.length() && source == null; i++) {
switch (token.charAt(i)) {
case '~':
isTilde = true;
isInput = false;
break;
case '+':
isInput = true;
isOutput = true;
break;
case '=':
isInput = false;
isOutput = true;
break;
case '*':
isMemory = true;
break;
default:
source = token.substring(i);
break;
}
}
if (isTilde) {
continue;
}
int start = source.indexOf('{');
int end = source.lastIndexOf('}');
if (start != -1 && end != -1) {
registerName = source.substring(start + 1, end);
}
assert registerName == null || AsmRegisterOperand.isRegister(registerName);
int idIn = index;
int idOut = outIndex;
Type type;
if (isInput) {
type = argTypes[index++];
} else if (retType instanceof StructureType) {
if (isMemory) {
type = new PointerType(retType);
idOut = index++;
} else {
type = alloca.getType(outIndex++);
}
} else if (isOutput) {
type = retType;
if (isMemory) {
idOut = index++;
}
} else {
throw new AssertionError("neither input nor output");
}
argInfo.add(new Argument(isInput, isOutput, isMemory, type, argInfo.size(), idIn, idOut, source, registerName));
}
assert index == argTypes.length;
assert retType instanceof StructureType ? outIndex == alloca.getOffsets().length : outIndex == 0;
}
LLVMInlineAssemblyRootNode finishInline() {
getArguments();
return new LLVMInlineAssemblyRootNode(null, null, frameDescriptor, statements.toArray(new LLVMExpressionNode[statements.size()]), arguments, result);
}
void createOperation(String operation) {
switch (operation) {
case "clc":
case "cld":
case "cli":
case "cmc":
case "lahf":
case "popfw":
case "pushfw":
case "sahf":
case "stc":
case "std":
case "sti":
statements.add(new LLVMI32UnsupportedInlineAssemblerNode(null));
return;
case "nop":
break;
case "rdtsc": {
LLVMAMD64WriteI64RegisterNode high = getRegisterStore("rdx");
LLVMAMD64WriteI64RegisterNode low = getRegisterStore("rax");
statements.add(LLVMAMD64RdtscNodeGen.create(low, high));
break;
}
default:
statements.add(new LLVMI32UnsupportedInlineAssemblerNode(null));
return;
}
}
void createUnaryOperation(String operation, AsmOperand operand) {
LLVMExpressionNode src;
LLVMExpressionNode out;
AsmOperand dst = operand;
Type dstType;
assert operation.length() > 0;
switch (operation.charAt(operation.length() - 1)) {
case 'b':
src = getOperandLoad(PrimitiveType.I8, operand);
dstType = PrimitiveType.I8;
break;
case 'w':
src = getOperandLoad(PrimitiveType.I16, operand);
dstType = PrimitiveType.I16;
break;
case 'l':
src = getOperandLoad(PrimitiveType.I32, operand);
dstType = PrimitiveType.I32;
break;
case 'q':
src = getOperandLoad(PrimitiveType.I64, operand);
dstType = PrimitiveType.I64;
break;
default:
src = null;
dstType = PrimitiveType.I64;
}
switch (operation) {
case "incb":
out = LLVMAMD64IncbNodeGen.create(src);
break;
case "incw":
out = LLVMAMD64IncwNodeGen.create(src);
break;
case "incl":
out = LLVMAMD64InclNodeGen.create(src);
break;
case "incq":
out = LLVMAMD64IncqNodeGen.create(src);
break;
case "decb":
out = LLVMAMD64DecbNodeGen.create(src);
break;
case "decw":
out = LLVMAMD64DecwNodeGen.create(src);
break;
case "decl":
out = LLVMAMD64DeclNodeGen.create(src);
break;
case "decq":
out = LLVMAMD64DecqNodeGen.create(src);
break;
case "negb":
out = LLVMAMD64NegbNodeGen.create(src);
break;
case "negw":
out = LLVMAMD64NegwNodeGen.create(src);
break;
case "negl":
out = LLVMAMD64NeglNodeGen.create(src);
break;
case "negq":
out = LLVMAMD64NegqNodeGen.create(src);
break;
case "notb":
out = LLVMAMD64NotbNodeGen.create(src);
break;
case "notw":
out = LLVMAMD64NotwNodeGen.create(src);
break;
case "notl":
out = LLVMAMD64NotlNodeGen.create(src);
break;
case "notq":
out = LLVMAMD64NotqNodeGen.create(src);
break;
case "idivb":
out = LLVMAMD64IdivbNodeGen.create(getOperandLoad(PrimitiveType.I16, new AsmRegisterOperand("ax")), src);
dst = new AsmRegisterOperand("ax");
dstType = PrimitiveType.I16;
break;
case "idivw": {
LLVMAMD64WriteI16RegisterNode rem = getRegisterStore("dx");
LLVMExpressionNode high = getOperandLoad(PrimitiveType.I16, new AsmRegisterOperand("dx"));
out = LLVMAMD64IdivwNodeGen.create(rem, high, getOperandLoad(PrimitiveType.I16, new AsmRegisterOperand("ax")), src);
dst = new AsmRegisterOperand("ax");
dstType = PrimitiveType.I16;
break;
}
case "idivl": {
LLVMAMD64WriteI32RegisterNode rem = getRegisterStore("edx");
LLVMExpressionNode high = getOperandLoad(PrimitiveType.I32, new AsmRegisterOperand("edx"));
out = LLVMAMD64IdivlNodeGen.create(rem, high, getOperandLoad(PrimitiveType.I32, new AsmRegisterOperand("eax")), src);
dst = new AsmRegisterOperand("eax");
dstType = PrimitiveType.I32;
break;
}
case "idivq": {
LLVMAMD64WriteI64RegisterNode rem = getRegisterStore("rdx");
LLVMExpressionNode high = getOperandLoad(PrimitiveType.I32, new AsmRegisterOperand("rdx"));
out = LLVMAMD64IdivqNodeGen.create(rem, high, getOperandLoad(PrimitiveType.I64, new AsmRegisterOperand("rax")), src);
dst = new AsmRegisterOperand("rax");
dstType = PrimitiveType.I64;
break;
}
case "imulb":
out = LLVMAMD64ImulbNodeGen.create(getOperandLoad(PrimitiveType.I16, new AsmRegisterOperand("ax")), src);
dst = new AsmRegisterOperand("ax");
dstType = PrimitiveType.I16;
break;
case "imulw": {
LLVMAMD64WriteI16RegisterNode high = getRegisterStore("dx");
out = LLVMAMD64ImulwNodeGen.create(high, getOperandLoad(PrimitiveType.I16, new AsmRegisterOperand("ax")), src);
dst = new AsmRegisterOperand("ax");
dstType = PrimitiveType.I16;
break;
}
case "imull": {
LLVMAMD64WriteI32RegisterNode high = getRegisterStore("edx");
out = LLVMAMD64ImullNodeGen.create(high, getOperandLoad(PrimitiveType.I32, new AsmRegisterOperand("eax")), src);
dst = new AsmRegisterOperand("eax");
dstType = PrimitiveType.I32;
break;
}
case "imulq": {
LLVMAMD64WriteI64RegisterNode high = getRegisterStore("rdx");
out = LLVMAMD64ImulqNodeGen.create(high, getOperandLoad(PrimitiveType.I64, new AsmRegisterOperand("rax")), src);
dst = new AsmRegisterOperand("rax");
dstType = PrimitiveType.I64;
break;
}
// TODO: implement properly
case "divb":
out = LLVMAMD64IdivbNodeGen.create(getOperandLoad(PrimitiveType.I16, new AsmRegisterOperand("ax")), src);
dst = new AsmRegisterOperand("ax");
dstType = PrimitiveType.I16;
break;
case "divw": {
LLVMAMD64WriteI16RegisterNode rem = getRegisterStore("dx");
LLVMExpressionNode high = getOperandLoad(PrimitiveType.I16, new AsmRegisterOperand("dx"));
out = LLVMAMD64IdivwNodeGen.create(rem, high, getOperandLoad(PrimitiveType.I16, new AsmRegisterOperand("ax")), src);
dst = new AsmRegisterOperand("ax");
dstType = PrimitiveType.I16;
break;
}
case "divl": {
LLVMAMD64WriteI32RegisterNode rem = getRegisterStore("edx");
LLVMExpressionNode high = getOperandLoad(PrimitiveType.I32, new AsmRegisterOperand("edx"));
out = LLVMAMD64IdivlNodeGen.create(rem, high, getOperandLoad(PrimitiveType.I32, new AsmRegisterOperand("eax")), src);
dst = new AsmRegisterOperand("eax");
dstType = PrimitiveType.I32;
break;
}
case "divq": {
LLVMAMD64WriteI64RegisterNode rem = getRegisterStore("rdx");
LLVMExpressionNode high = getOperandLoad(PrimitiveType.I32, new AsmRegisterOperand("rdx"));
out = LLVMAMD64IdivqNodeGen.create(rem, high, getOperandLoad(PrimitiveType.I64, new AsmRegisterOperand("rax")), src);
dst = new AsmRegisterOperand("rax");
dstType = PrimitiveType.I64;
break;
}
case "mulb":
src = getOperandLoad(PrimitiveType.I16, operand);
out = LLVMAMD64MulbNodeGen.create(getOperandLoad(PrimitiveType.I16, new AsmRegisterOperand("ax")), src);
dst = new AsmRegisterOperand("ax");
dstType = PrimitiveType.I16;
break;
case "mulw": {
LLVMAMD64WriteI16RegisterNode high = getRegisterStore("dx");
out = LLVMAMD64MulwNodeGen.create(high, getOperandLoad(PrimitiveType.I16, new AsmRegisterOperand("ax")), src);
dst = new AsmRegisterOperand("ax");
dstType = PrimitiveType.I16;
break;
}
case "mull": {
LLVMAMD64WriteI32RegisterNode high = getRegisterStore("edx");
out = LLVMAMD64MullNodeGen.create(high, getOperandLoad(PrimitiveType.I32, new AsmRegisterOperand("eax")), src);
dst = new AsmRegisterOperand("eax");
dstType = PrimitiveType.I32;
break;
}
case "mulq": {
LLVMAMD64WriteI64RegisterNode high = getRegisterStore("rdx");
out = LLVMAMD64MulqNodeGen.create(high, getOperandLoad(PrimitiveType.I64, new AsmRegisterOperand("rax")), src);
dst = new AsmRegisterOperand("rax");
dstType = PrimitiveType.I64;
break;
}
default:
statements.add(new LLVMI32UnsupportedInlineAssemblerNode(null));
return;
}
LLVMExpressionNode write = getOperandStore(dstType, dst, out);
statements.add(write);
}
void createBinaryOperation(String operation, AsmOperand a, AsmOperand b) {
LLVMExpressionNode srcA;
LLVMExpressionNode srcB;
LLVMExpressionNode out;
AsmOperand dst = b;
Type dstType;
switch (operation.charAt(operation.length() - 1)) {
case 'b':
srcA = getOperandLoad(PrimitiveType.I8, a);
srcB = getOperandLoad(PrimitiveType.I8, b);
dstType = PrimitiveType.I8;
break;
case 'w':
srcA = getOperandLoad(PrimitiveType.I16, a);
srcB = getOperandLoad(PrimitiveType.I16, b);
dstType = PrimitiveType.I16;
break;
case 'l':
srcA = getOperandLoad(PrimitiveType.I32, a);
srcB = getOperandLoad(PrimitiveType.I32, b);
dstType = PrimitiveType.I32;
break;
case 'q':
srcA = getOperandLoad(PrimitiveType.I64, a);
srcB = getOperandLoad(PrimitiveType.I64, b);
dstType = PrimitiveType.I64;
break;
default:
srcA = null;
srcB = null;
dstType = PrimitiveType.I8;
}
switch (operation) {
case "addb":
out = LLVMAMD64AddbNodeGen.create(srcA, srcB);
break;
case "addw":
out = LLVMAMD64AddwNodeGen.create(srcA, srcB);
break;
case "addl":
out = LLVMAMD64AddlNodeGen.create(srcA, srcB);
break;
case "addq":
out = LLVMAMD64AddqNodeGen.create(srcA, srcB);
break;
case "subb":
out = LLVMAMD64SubbNodeGen.create(srcB, srcA);
break;
case "subw":
out = LLVMAMD64SubwNodeGen.create(srcB, srcA);
break;
case "subl":
out = LLVMAMD64SublNodeGen.create(srcB, srcA);
break;
case "subq":
out = LLVMAMD64SubqNodeGen.create(srcB, srcA);
break;
case "idivb":
srcA = getOperandLoad(PrimitiveType.I8, a);
srcB = getOperandLoad(PrimitiveType.I16, b);
out = LLVMAMD64IdivbNodeGen.create(srcB, srcA);
dst = new AsmRegisterOperand("ax");
dstType = PrimitiveType.I16;
break;
case "idivw": {
LLVMAMD64WriteI16RegisterNode rem = getRegisterStore("dx");
LLVMExpressionNode high = getOperandLoad(PrimitiveType.I16, new AsmRegisterOperand("dx"));
out = LLVMAMD64IdivwNodeGen.create(rem, high, srcB, srcA);
dst = new AsmRegisterOperand("ax");
break;
}
case "idivl": {
LLVMAMD64WriteI32RegisterNode rem = getRegisterStore("edx");
LLVMExpressionNode high = getOperandLoad(PrimitiveType.I32, new AsmRegisterOperand("edx"));
out = LLVMAMD64IdivlNodeGen.create(rem, high, srcB, srcA);
dst = new AsmRegisterOperand("eax");
break;
}
case "idivq": {
LLVMAMD64WriteI64RegisterNode rem = getRegisterStore("rdx");
LLVMExpressionNode high = getOperandLoad(PrimitiveType.I32, new AsmRegisterOperand("rdx"));
out = LLVMAMD64IdivqNodeGen.create(rem, high, srcB, srcA);
dst = new AsmRegisterOperand("rax");
break;
}
case "imulb":
srcA = getOperandLoad(PrimitiveType.I16, a);
srcB = getOperandLoad(PrimitiveType.I8, b);
out = LLVMAMD64ImulbNodeGen.create(srcA, srcB);
dstType = PrimitiveType.I16;
break;
case "imulw": {
LLVMAMD64WriteI16RegisterNode high = getRegisterStore("dx");
out = LLVMAMD64ImulwNodeGen.create(high, srcA, srcB);
break;
}
case "imull": {
LLVMAMD64WriteI32RegisterNode high = getRegisterStore("edx");
out = LLVMAMD64ImullNodeGen.create(high, srcA, srcB);
break;
}
case "imulq": {
LLVMAMD64WriteI64RegisterNode high = getRegisterStore("rdx");
out = LLVMAMD64ImulqNodeGen.create(high, srcA, srcB);
break;
}
case "movb":
case "movw":
case "movl":
case "movq":
out = srcA;
break;
case "salb":
out = LLVMAMD64SalbNodeGen.create(srcB, srcA);
break;
case "salw":
out = LLVMAMD64SalwNodeGen.create(srcB, srcA);
break;
case "sall":
out = LLVMAMD64SallNodeGen.create(srcB, srcA);
break;
case "salq":
out = LLVMAMD64SalqNodeGen.create(srcB, srcA);
break;
case "sarb":
out = LLVMAMD64SarbNodeGen.create(srcB, srcA);
break;
case "sarw":
out = LLVMAMD64SarwNodeGen.create(srcB, srcA);
break;
case "sarl":
out = LLVMAMD64SarlNodeGen.create(srcB, srcA);
break;
case "sarq":
out = LLVMAMD64SarqNodeGen.create(srcB, srcA);
break;
case "shlb":
out = LLVMAMD64ShlbNodeGen.create(srcB, srcA);
break;
case "shlw":
out = LLVMAMD64ShlwNodeGen.create(srcB, srcA);
break;
case "shll":
out = LLVMAMD64ShllNodeGen.create(srcB, srcA);
break;
case "shlq":
out = LLVMAMD64ShlqNodeGen.create(srcB, srcA);
break;
case "shrb":
out = LLVMAMD64ShrbNodeGen.create(srcB, srcA);
break;
case "shrw":
out = LLVMAMD64ShrwNodeGen.create(srcB, srcA);
break;
case "shrl":
out = LLVMAMD64ShrlNodeGen.create(srcB, srcA);
break;
case "shrq":
out = LLVMAMD64ShrqNodeGen.create(srcB, srcA);
break;
case "andb":
out = LLVMAMD64AndbNodeGen.create(srcA, srcB);
break;
case "andw":
out = LLVMAMD64AndwNodeGen.create(srcA, srcB);
break;
case "andl":
out = LLVMAMD64AndlNodeGen.create(srcA, srcB);
break;
case "andq":
out = LLVMAMD64AndqNodeGen.create(srcA, srcB);
break;
case "orb":
out = LLVMAMD64OrbNodeGen.create(srcA, srcB);
break;
case "orw":
out = LLVMAMD64OrwNodeGen.create(srcA, srcB);
break;
case "orl":
out = LLVMAMD64OrlNodeGen.create(srcA, srcB);
break;
case "orq":
out = LLVMAMD64OrqNodeGen.create(srcA, srcB);
break;
case "xorb":
out = LLVMAMD64XorbNodeGen.create(srcA, srcB);
break;
case "xorw":
out = LLVMAMD64XorwNodeGen.create(srcA, srcB);
break;
case "xorl":
out = LLVMAMD64XorlNodeGen.create(srcA, srcB);
break;
case "xorq":
out = LLVMAMD64XorqNodeGen.create(srcA, srcB);
break;
default:
statements.add(new LLVMI32UnsupportedInlineAssemblerNode(null));
return;
}
LLVMExpressionNode write = getOperandStore(dstType, dst, out);
statements.add(write);
}
@SuppressWarnings("unused")
public void createTernaryOperation(String op, AsmOperand a, AsmOperand b, AsmOperand c) {
}
void addFrameSlot(String reg, Type type) {
if (!registers.contains(reg)) {
registers.add(reg);
FrameSlotKind kind;
if (type instanceof PrimitiveType) {
PrimitiveKind primitiveKind = ((PrimitiveType) type).getPrimitiveKind();
switch (primitiveKind) {
case I8:
kind = FrameSlotKind.Byte;
break;
case I32:
kind = FrameSlotKind.Int;
break;
case I64:
kind = FrameSlotKind.Long;
break;
default:
kind = FrameSlotKind.Illegal;
break;
}
} else {
kind = FrameSlotKind.Illegal;
}
this.frameDescriptor.addFrameSlot(reg, kind);
}
}
private void getArguments() {
LLVMAllocaConstInstruction alloca = null;
LLVMStructWriteNode[] writeNodes = null;
LLVMExpressionNode[] valueNodes = null;
if (retType instanceof StructureType) {
assert args[0] instanceof LLVMAllocaConstInstruction;
alloca = (LLVMAllocaConstInstruction) args[0];
writeNodes = new LLVMStructWriteNode[alloca.getLength()];
valueNodes = new LLVMExpressionNode[alloca.getLength()];
}
Set<String> todoRegisters = new HashSet<>(registers);
for (Argument arg : argInfo) {
// output register
if (arg.isOutput()) {
FrameSlot slot = null;
if (arg.isRegister()) {
slot = getRegisterSlot(arg.getRegister());
LLVMExpressionNode register = LLVMI64ReadNodeGen.create(slot);
if (retType instanceof StructureType) {
assert alloca.getType(arg.getOutIndex()) == arg.getType();
PrimitiveKind primitiveKind = ((PrimitiveType) arg.getType()).getPrimitiveKind();
switch (primitiveKind) {
case I8:
valueNodes[arg.getOutIndex()] = LLVMToI8NoZeroExtNodeGen.create(register);
writeNodes[arg.getOutIndex()] = LLVMPrimitiveStructWriteNodeGen.create();
break;
case I16:
valueNodes[arg.getOutIndex()] = LLVMToI16NoZeroExtNodeGen.create(register);
writeNodes[arg.getOutIndex()] = LLVMPrimitiveStructWriteNodeGen.create();
break;
case I32:
valueNodes[arg.getOutIndex()] = LLVMToI32NoZeroExtNodeGen.create(register);
writeNodes[arg.getOutIndex()] = LLVMPrimitiveStructWriteNodeGen.create();
break;
case I64:
valueNodes[arg.getOutIndex()] = register;
writeNodes[arg.getOutIndex()] = LLVMPrimitiveStructWriteNodeGen.create();
break;
default:
throw new AsmParseException("invalid operand size");
}
} else {
result = castResult(register);
}
} else {
slot = getArgumentSlot(arg.getIndex(), retType);
if (retType instanceof PrimitiveType) {
handlePrimitive(slot);
} else if (retType instanceof StructureType) {
PrimitiveKind primitiveKind = ((PrimitiveType) arg.getType()).getPrimitiveKind();
switch (primitiveKind) {
case I8:
valueNodes[arg.getOutIndex()] = LLVMI8ReadNodeGen.create(slot);
writeNodes[arg.getOutIndex()] = LLVMPrimitiveStructWriteNodeGen.create();
break;
case I16:
valueNodes[arg.getOutIndex()] = LLVMI16ReadNodeGen.create(slot);
writeNodes[arg.getOutIndex()] = LLVMPrimitiveStructWriteNodeGen.create();
break;
case I32:
valueNodes[arg.getOutIndex()] = LLVMI32ReadNodeGen.create(slot);
writeNodes[arg.getOutIndex()] = LLVMPrimitiveStructWriteNodeGen.create();
break;
case I64:
valueNodes[arg.getOutIndex()] = LLVMI64ReadNodeGen.create(slot);
writeNodes[arg.getOutIndex()] = LLVMPrimitiveStructWriteNodeGen.create();
break;
default:
throw new AsmParseException("invalid operand size");
}
} else if (retType instanceof PointerType) {
result = LLVMAddressReadNodeGen.create(slot);
} else if (retType instanceof VoidType) {
result = null;
} else {
throw new AsmParseException("invalid operand size: " + retType);
}
}
}
// input register
if (arg.isInput()) {
FrameSlot slot = null;
if (arg.isRegister()) {
String reg = AsmRegisterOperand.getBaseRegister(arg.getRegister());
slot = getRegisterSlot(reg);
todoRegisters.remove(reg);
LLVMExpressionNode argnode = LLVMArgNodeGen.create(arg.getInIndex());
LLVMExpressionNode node = LLVMToI64NoZeroExtNodeGen.create(argnode);
arguments.add(LLVMWriteI64NodeGen.create(node, slot, null));
}
slot = getArgumentSlot(arg.getIndex(), argTypes[arg.getInIndex()]);
LLVMExpressionNode argnode = LLVMArgNodeGen.create(arg.getInIndex());
if (arg.getType() instanceof PrimitiveType) {
handlePrimitiveArgument(arg.getType(), slot, argnode);
} else if (arg.getType() instanceof PointerType) {
arguments.add(LLVMWriteAddressNodeGen.create(argnode, slot, null));
} else {
throw new AsmParseException("invalid operand size: " + arg.getType());
}
}
}
if (retType instanceof StructureType) {
LLVMExpressionNode addrArg = LLVMArgNodeGen.create(0);
FrameSlot slot = frameDescriptor.addFrameSlot("returnValue", FrameSlotKind.Object);
LLVMWriteAddressNode writeAddr = LLVMWriteAddressNodeGen.create(addrArg, slot, null);
statements.add(writeAddr);
LLVMExpressionNode addr = LLVMAddressReadNodeGen.create(slot);
this.result = new StructLiteralNode(alloca.getOffsets(), writeNodes, valueNodes, addr);
}
// initialize registers
for (String register : todoRegisters) {
if (register.startsWith("$")) {
continue;
}
LLVMExpressionNode node = LLVMAMD64I64NodeGen.create(0);
FrameSlot slot = getRegisterSlot(register);
arguments.add(LLVMWriteI64NodeGen.create(node, slot, null));
}
assert retType instanceof VoidType || retType != null;
}
private void handlePrimitiveArgument(Type argType, FrameSlot slot, LLVMExpressionNode argnode) {
switch (((PrimitiveType) argType).getPrimitiveKind()) {
case I8:
arguments.add(LLVMWriteI8NodeGen.create(argnode, slot, null));
break;
case I16:
arguments.add(LLVMWriteI16NodeGen.create(argnode, slot, null));
break;
case I32:
arguments.add(LLVMWriteI32NodeGen.create(argnode, slot, null));
break;
case I64:
arguments.add(LLVMWriteI64NodeGen.create(argnode, slot, null));
break;
case FLOAT:
arguments.add(LLVMWriteFloatNodeGen.create(argnode, slot, null));
break;
case DOUBLE:
arguments.add(LLVMWriteDoubleNodeGen.create(argnode, slot, null));
break;
default:
throw new AsmParseException("invalid operand size: " + argType);
}
}
private void handlePrimitive(FrameSlot slot) {
switch (((PrimitiveType) retType).getPrimitiveKind()) {
case I8:
result = LLVMI8ReadNodeGen.create(slot);
break;
case I16:
result = LLVMI16ReadNodeGen.create(slot);
break;
case I32:
result = LLVMI32ReadNodeGen.create(slot);
break;
case I64:
result = LLVMI64ReadNodeGen.create(slot);
break;
case FLOAT:
result = LLVMFloatReadNodeGen.create(slot);
break;
case DOUBLE:
result = LLVMDoubleReadNodeGen.create(slot);
break;
default:
throw new AsmParseException("invalid operand size: " + retType);
}
}
private LLVMExpressionNode castResult(LLVMExpressionNode register) {
switch (((PrimitiveType) retType).getPrimitiveKind()) {
case I8:
return LLVMToI8NoZeroExtNodeGen.create(register);
case I16:
return LLVMToI16NoZeroExtNodeGen.create(register);
case I32:
return LLVMToI32NoZeroExtNodeGen.create(register);
case I64:
return register;
default:
return new LLVMUnsupportedInlineAssemblerNode(null);
}
}
private LLVMExpressionNode getOperandLoad(Type type, AsmOperand operand) {
if (operand instanceof AsmRegisterOperand) {
AsmRegisterOperand op = (AsmRegisterOperand) operand;
FrameSlot frame = getRegisterSlot(op.getBaseRegister());
LLVMExpressionNode register = LLVMI64ReadNodeGen.create(frame);
assert type == op.getWidth();
switch (((PrimitiveType) op.getWidth()).getPrimitiveKind()) {
case I8:
return LLVMToI8NoZeroExtNodeGen.create(register);
case I16:
return LLVMToI16NoZeroExtNodeGen.create(register);
case I32:
return LLVMToI32NoZeroExtNodeGen.create(register);
case I64:
return register;
default:
throw new AsmParseException("invalid operand size");
}
} else if (operand instanceof AsmImmediateOperand) {
AsmImmediateOperand op = (AsmImmediateOperand) operand;
if (op.isLabel()) {
throw new AsmParseException("labels not supported");
} else {
switch (((PrimitiveType) type).getPrimitiveKind()) {
case I8:
return LLVMAMD64I8NodeGen.create((byte) op.getValue());
case I16:
return LLVMAMD64I16NodeGen.create((short) op.getValue());
case I32:
return LLVMAMD64I32NodeGen.create((int) op.getValue());
case I64:
return LLVMAMD64I64NodeGen.create(op.getValue());
default:
throw new AsmParseException("invalid dst type");
}
}
} else if (operand instanceof AsmArgumentOperand) {
AsmArgumentOperand op = (AsmArgumentOperand) operand;
Argument info = argInfo.get(op.getIndex());
FrameSlot frame = getArgumentSlot(op.getIndex(), type);
if (info.isMemory()) {
switch (((PrimitiveType) type).getPrimitiveKind()) {
case I8:
return LLVMI8LoadNodeGen.create(LLVMAddressReadNodeGen.create(frame));
case I16:
return LLVMI16LoadNodeGen.create(LLVMAddressReadNodeGen.create(frame));
case I32:
return LLVMI32LoadNodeGen.create(LLVMAddressReadNodeGen.create(frame));
case I64:
return LLVMI64LoadNodeGen.create(LLVMAddressReadNodeGen.create(frame));
default:
throw new AsmParseException("invalid operand size");
}
} else {
assert type == info.getType();
switch (((PrimitiveType) type).getPrimitiveKind()) {
case I8:
return LLVMI8ReadNodeGen.create(frame);
case I16:
return LLVMI16ReadNodeGen.create(frame);
case I32:
return LLVMI32ReadNodeGen.create(frame);
case I64:
return LLVMI64ReadNodeGen.create(frame);
default:
throw new AsmParseException("invalid operand size");
}
}
}
throw new AsmParseException("unsupported operand type: " + operand);
}
private LLVMExpressionNode getOperandStore(Type type, AsmOperand operand, LLVMExpressionNode from) {
if (operand instanceof AsmRegisterOperand) {
AsmRegisterOperand op = (AsmRegisterOperand) operand;
FrameSlot frame = getRegisterSlot(op.getBaseRegister());
LLVMExpressionNode register = LLVMI64ReadNodeGen.create(frame);
int shift = op.getShift();
LLVMExpressionNode out = null;
assert type == op.getWidth();
switch (((PrimitiveType) op.getWidth()).getPrimitiveKind()) {
case I8:
out = LLVMI8ToR64NodeGen.create(shift, register, from);
break;
case I16:
out = LLVMI16ToR64NodeGen.create(register, from);
break;
case I32:
out = LLVMI32ToR64NodeGen.create(register, from);
break;
case I64:
out = from;
break;
default:
throw new AsmParseException("unsupported operand size");
}
return LLVMWriteI64NodeGen.create(out, frame, null);
} else if (operand instanceof AsmArgumentOperand) {
AsmArgumentOperand op = (AsmArgumentOperand) operand;
Argument info = argInfo.get(op.getIndex());
if (info.isMemory()) {
LLVMExpressionNode address = info.getAddress();
switch (((PrimitiveType) type).getPrimitiveKind()) {
case I8:
return LLVMI8StoreNodeGen.create(null, address, from);
case I16:
return LLVMI16StoreNodeGen.create(null, address, from);
case I32:
return LLVMI32StoreNodeGen.create(null, address, from);
case I64:
return LLVMI64StoreNodeGen.create(null, address, from);
default:
throw new AsmParseException("invalid operand size");
}
} else {
assert type == info.getType();
FrameSlot frame = getArgumentSlot(op.getIndex(), type);
switch (((PrimitiveType) type).getPrimitiveKind()) {
case I8:
return LLVMWriteI8NodeGen.create(from, frame, null);
case I16:
return LLVMWriteI16NodeGen.create(from, frame, null);
case I32:
return LLVMWriteI32NodeGen.create(from, frame, null);
case I64:
return LLVMWriteI64NodeGen.create(from, frame, null);
default:
throw new AsmParseException("invalid operand size");
}
}
}
throw new AsmParseException("unsupported operand type: " + operand);
}
@SuppressWarnings("unchecked")
private <T extends LLVMAMD64WriteRegisterNode> T getRegisterStore(String name) {
AsmRegisterOperand op = new AsmRegisterOperand(name);
FrameSlot frame = getRegisterSlot(name);
LLVMExpressionNode register = LLVMI64ReadNodeGen.create(frame);
LLVMAMD64WriteRegisterNode node = null;
switch (((PrimitiveType) op.getWidth()).getPrimitiveKind()) {
case I16:
node = new LLVMAMD64WriteI16RegisterNode(frame, register);
break;
case I32:
node = new LLVMAMD64WriteI32RegisterNode(frame, register);
break;
case I64:
node = new LLVMAMD64WriteI64RegisterNode(frame);
break;
default:
throw new AsmParseException("unsupported operand type");
}
return (T) node;
}
private FrameSlot getRegisterSlot(String name) {
AsmRegisterOperand op = new AsmRegisterOperand(name);
String baseRegister = op.getBaseRegister();
addFrameSlot(baseRegister, PrimitiveType.I64);
FrameSlot frame = frameDescriptor.findFrameSlot(baseRegister);
return frame;
}
private static String getArgumentName(int index) {
return "$" + index;
}
private FrameSlot getArgumentSlot(int index, Type type) {
Argument info = argInfo.get(index);
assert info.isMemory() || type == info.getType();
String name = getArgumentName(index);
addFrameSlot(name, type);
return frameDescriptor.findFrameSlot(name);
}
}