diff --git a/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java index b1a2b45..d2c1d40 100644 --- a/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java +++ b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java @@ -4,7 +4,7 @@ import com.compilerprogramming.ezlang.parser.AST; import com.compilerprogramming.ezlang.types.Scope; import com.compilerprogramming.ezlang.types.Symbol; -import com.compilerprogramming.ezlang.types.Type; +import com.compilerprogramming.ezlang.types.EZType; import com.compilerprogramming.ezlang.types.TypeDictionary; import java.util.*; @@ -17,7 +17,7 @@ public class CompiledFunction { public BasicBlock currentBlock; private BasicBlock currentBreakTarget; private BasicBlock currentContinueTarget; - public Type.TypeFunction functionType; + public EZType.EZTypeFunction functionType; public final RegisterPool registerPool; private final TypeDictionary typeDictionary; @@ -39,7 +39,7 @@ public class CompiledFunction { public CompiledFunction(Symbol.FunctionTypeSymbol functionSymbol, TypeDictionary typeDictionary, EnumSet options) { AST.FuncDecl funcDecl = (AST.FuncDecl) functionSymbol.functionDecl; - this.functionType = (Type.TypeFunction) functionSymbol.type; + this.functionType = (EZType.EZTypeFunction) functionSymbol.type; this.registerPool = new RegisterPool(); // Incremental SSA is an optional feature this.issa = (options != null && options.contains(Options.ISSA)) ? new IncrementalSSABraun(this) : new NoopIncrementalSSA(); @@ -60,8 +60,8 @@ public CompiledFunction(Symbol.FunctionTypeSymbol functionSymbol, TypeDictionary public CompiledFunction(Symbol.FunctionTypeSymbol functionSymbol, TypeDictionary typeDictionary) { this(functionSymbol,typeDictionary,null); } - public CompiledFunction(Type.TypeFunction functionType, TypeDictionary typeDictionary) { - this.functionType = (Type.TypeFunction) functionType; + public CompiledFunction(EZType.EZTypeFunction functionType, TypeDictionary typeDictionary) { + this.functionType = (EZType.EZTypeFunction) functionType; this.registerPool = new RegisterPool(); this.issa = new NoopIncrementalSSA(); this.BID = 0; this.entry = this.currentBlock = createBlock(); @@ -325,7 +325,7 @@ private boolean compileExpr(AST.Expr expr) { private boolean compileCallExpr(AST.CallExpr callExpr) { compileExpr(callExpr.callee); var callee = pop(); - Type.TypeFunction calleeType = null; + EZType.EZTypeFunction calleeType = null; if (callee instanceof Operand.LocalFunctionOperand functionOperand) calleeType = functionOperand.functionType; else throw new CompilerException("Cannot call a non function type"); @@ -347,20 +347,20 @@ private boolean compileCallExpr(AST.CallExpr callExpr) { for (int i = 0; i < args.size(); i++) pop(); Operand.TempRegisterOperand ret = null; - if (callExpr.callee.type instanceof Type.TypeFunction tf && - !(tf.returnType instanceof Type.TypeVoid)) { + if (callExpr.callee.type instanceof EZType.EZTypeFunction tf && + !(tf.returnType instanceof EZType.EZTypeVoid)) { ret = createTemp(tf.returnType); } codeCall(returnStackPos, ret, calleeType, args.toArray(new Operand.RegisterOperand[args.size()])); return false; } - private Type.TypeStruct getStructType(Type t) { - if (t instanceof Type.TypeStruct typeStruct) { + private EZType.EZTypeStruct getStructType(EZType t) { + if (t instanceof EZType.EZTypeStruct typeStruct) { return typeStruct; } - else if (t instanceof Type.TypeNullable ptr && - ptr.baseType instanceof Type.TypeStruct typeStruct) { + else if (t instanceof EZType.EZTypeNullable ptr && + ptr.baseType instanceof EZType.EZTypeStruct typeStruct) { return typeStruct; } else @@ -368,7 +368,7 @@ else if (t instanceof Type.TypeNullable ptr && } private boolean compileFieldExpr(AST.GetFieldExpr fieldExpr) { - Type.TypeStruct typeStruct = getStructType(fieldExpr.object.type); + EZType.EZTypeStruct typeStruct = getStructType(fieldExpr.object.type); int fieldIndex = typeStruct.getFieldIndex(fieldExpr.fieldName); if (fieldIndex < 0) throw new CompilerException("Field " + fieldExpr.fieldName + " not found"); @@ -391,7 +391,7 @@ private boolean compileArrayIndexExpr(AST.ArrayLoadExpr arrayIndexExpr) { } private boolean compileSetFieldExpr(AST.SetFieldExpr setFieldExpr) { - Type.TypeStruct structType = (Type.TypeStruct) setFieldExpr.object.type; + EZType.EZTypeStruct structType = (EZType.EZTypeStruct) setFieldExpr.object.type; int fieldIndex = structType.getFieldIndex(setFieldExpr.fieldName); if (fieldIndex == -1) throw new CompilerException("Field " + setFieldExpr.fieldName + " not found in struct " + structType.name); @@ -441,7 +441,7 @@ private boolean compileInitExpr(AST.InitExpr initExpr) { } private boolean compileSymbolExpr(AST.NameExpr symbolExpr) { - if (symbolExpr.type instanceof Type.TypeFunction functionType) + if (symbolExpr.type instanceof EZType.EZTypeFunction functionType) pushOperand(new Operand.LocalFunctionOperand(functionType)); else { Symbol.VarSymbol varSymbol = (Symbol.VarSymbol) symbolExpr.symbol; @@ -549,29 +549,29 @@ private boolean compileUnaryExpr(AST.UnaryExpr unaryExpr) { } private boolean compileConstantExpr(AST.LiteralExpr constantExpr) { - if (constantExpr.type instanceof Type.TypeInteger) + if (constantExpr.type instanceof EZType.EZTypeInteger) pushConstant(constantExpr.value.num.intValue(), constantExpr.type); - else if (constantExpr.type instanceof Type.TypeNull) + else if (constantExpr.type instanceof EZType.EZTypeNull) pushNullConstant(constantExpr.type); else throw new CompilerException("Invalid constant type"); return false; } - private void pushConstant(long value, Type type) { + private void pushConstant(long value, EZType type) { pushOperand(new Operand.ConstantOperand(value, type)); } - private void pushNullConstant(Type type) { + private void pushNullConstant(EZType type) { pushOperand(new Operand.NullConstantOperand(type)); } - private Operand.TempRegisterOperand createTemp(Type type) { + private Operand.TempRegisterOperand createTemp(EZType type) { var tempRegister = new Operand.TempRegisterOperand(registerPool.newTempReg(type)); pushOperand(tempRegister); return tempRegister; } - Type typeOfOperand(Operand operand) { + EZType typeOfOperand(Operand operand) { if (operand instanceof Operand.ConstantOperand constant) return constant.type; else if (operand instanceof Operand.NullConstantOperand nullConstantOperand) @@ -582,7 +582,7 @@ else if (operand instanceof Operand.RegisterOperand registerOperand) } private Operand.TempRegisterOperand createTempAndMove(Operand src) { - Type type = typeOfOperand(src); + EZType type = typeOfOperand(src); var temp = createTemp(type); codeMove(src, temp); return temp; @@ -644,16 +644,16 @@ else if (indexed instanceof Operand.LoadFieldOperand loadFieldOperand) codeMove(value, indexed); } - private void codeNew(Type type, AST.Expr len, AST.Expr initVal) { - if (type instanceof Type.TypeArray typeArray) + private void codeNew(EZType type, AST.Expr len, AST.Expr initVal) { + if (type instanceof EZType.EZTypeArray typeArray) codeNewArray(typeArray, len, initVal); - else if (type instanceof Type.TypeStruct typeStruct) + else if (type instanceof EZType.EZTypeStruct typeStruct) codeNewStruct(typeStruct); else throw new CompilerException("Unexpected type: " + type); } - private void codeNewArray(Type.TypeArray typeArray, AST.Expr len, AST.Expr initVal) { + private void codeNewArray(EZType.EZTypeArray typeArray, AST.Expr len, AST.Expr initVal) { var temp = createTemp(typeArray); Operand lenOperand = null; Operand initValOperand = null; @@ -685,7 +685,7 @@ private void codeNewArray(Type.TypeArray typeArray, AST.Expr len, AST.Expr initV code(insn); } - private void codeNewStruct(Type.TypeStruct typeStruct) { + private void codeNewStruct(EZType.EZTypeStruct typeStruct) { var temp = createTemp(typeStruct); var target = (Operand.RegisterOperand) issa.write(temp); var insn = new Instruction.NewStruct(typeStruct, target); @@ -729,7 +729,7 @@ private void codeCBR(BasicBlock block, Operand condition, BasicBlock trueBlock, private void codeCall(int newBase, Operand.RegisterOperand targetOperand, - Type.TypeFunction calleeType, + EZType.EZTypeFunction calleeType, Operand.RegisterOperand ...arguments) { if (targetOperand != null) targetOperand = (Operand.RegisterOperand) issa.write(targetOperand); diff --git a/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Compiler.java b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Compiler.java index b15a157..7f33025 100644 --- a/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Compiler.java +++ b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Compiler.java @@ -5,7 +5,7 @@ import com.compilerprogramming.ezlang.semantic.SemaAssignTypes; import com.compilerprogramming.ezlang.semantic.SemaDefineTypes; import com.compilerprogramming.ezlang.types.Symbol; -import com.compilerprogramming.ezlang.types.Type; +import com.compilerprogramming.ezlang.types.EZType; import com.compilerprogramming.ezlang.types.TypeDictionary; import java.util.EnumSet; @@ -15,7 +15,7 @@ public class Compiler { private void compile(TypeDictionary typeDictionary, EnumSet options) { for (Symbol symbol: typeDictionary.getLocalSymbols()) { if (symbol instanceof Symbol.FunctionTypeSymbol functionSymbol) { - Type.TypeFunction functionType = (Type.TypeFunction) functionSymbol.type; + EZType.EZTypeFunction functionType = (EZType.EZTypeFunction) functionSymbol.type; var function = new CompiledFunction(functionSymbol, typeDictionary, options); if (options.contains(Options.DUMP_INITIAL_IR)) function.dumpIR(false, "Initial IR"); diff --git a/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Instruction.java b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Instruction.java index f7a3c6b..3ea0f44 100644 --- a/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Instruction.java +++ b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Instruction.java @@ -1,7 +1,7 @@ package com.compilerprogramming.ezlang.compiler; import com.compilerprogramming.ezlang.exceptions.CompilerException; -import com.compilerprogramming.ezlang.types.Type; +import com.compilerprogramming.ezlang.types.EZType; import java.util.ArrayList; import java.util.Collections; @@ -139,16 +139,16 @@ public StringBuilder toStr(StringBuilder sb) { } public static class NewArray extends Instruction { - public final Type.TypeArray type; - public NewArray(Type.TypeArray type, Operand.RegisterOperand destOperand) { + public final EZType.EZTypeArray type; + public NewArray(EZType.EZTypeArray type, Operand.RegisterOperand destOperand) { super(I_NEW_ARRAY, destOperand); this.type = type; } - public NewArray(Type.TypeArray type, Operand.RegisterOperand destOperand, Operand len) { + public NewArray(EZType.EZTypeArray type, Operand.RegisterOperand destOperand, Operand len) { super(I_NEW_ARRAY, destOperand, len); this.type = type; } - public NewArray(Type.TypeArray type, Operand.RegisterOperand destOperand, Operand len, Operand initValue) { + public NewArray(EZType.EZTypeArray type, Operand.RegisterOperand destOperand, Operand len, Operand initValue) { super(I_NEW_ARRAY, destOperand, len, initValue); this.type = type; } @@ -170,8 +170,8 @@ public StringBuilder toStr(StringBuilder sb) { } public static class NewStruct extends Instruction { - public final Type.TypeStruct type; - public NewStruct(Type.TypeStruct type, Operand.RegisterOperand destOperand) { + public final EZType.EZTypeStruct type; + public NewStruct(EZType.EZTypeStruct type, Operand.RegisterOperand destOperand) { super(I_NEW_STRUCT, destOperand); this.type = type; } @@ -324,9 +324,9 @@ public StringBuilder toStr(StringBuilder sb) { } public static class Call extends Instruction { - public final Type.TypeFunction callee; + public final EZType.EZTypeFunction callee; public final int newbase; - public Call(int newbase, Operand.RegisterOperand returnOperand, Type.TypeFunction callee, Operand.RegisterOperand... args) { + public Call(int newbase, Operand.RegisterOperand returnOperand, EZType.EZTypeFunction callee, Operand.RegisterOperand... args) { super(I_CALL, returnOperand, args); this.callee = callee; this.newbase = newbase; diff --git a/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Operand.java b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Operand.java index 8ff84e4..f6af988 100644 --- a/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Operand.java +++ b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Operand.java @@ -1,15 +1,15 @@ package com.compilerprogramming.ezlang.compiler; import com.compilerprogramming.ezlang.types.Symbol; -import com.compilerprogramming.ezlang.types.Type; +import com.compilerprogramming.ezlang.types.EZType; public class Operand { - Type type; + EZType type; public static class ConstantOperand extends Operand { public final long value; - public ConstantOperand(long value, Type type) { + public ConstantOperand(long value, EZType type) { this.value = value; this.type = type; } @@ -20,7 +20,7 @@ public String toString() { } public static class NullConstantOperand extends Operand { - public NullConstantOperand(Type type) { + public NullConstantOperand(EZType type) { this.type = type; } @Override @@ -61,8 +61,8 @@ public RegisterOperand copy(Register register) { } public static class LocalFunctionOperand extends Operand { - public final Type.TypeFunction functionType; - public LocalFunctionOperand(Type.TypeFunction functionType) { + public final EZType.EZTypeFunction functionType; + public LocalFunctionOperand(EZType.EZTypeFunction functionType) { this.functionType = functionType; } @Override diff --git a/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Register.java b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Register.java index 9f87393..09190a1 100644 --- a/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Register.java +++ b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Register.java @@ -1,6 +1,6 @@ package com.compilerprogramming.ezlang.compiler; -import com.compilerprogramming.ezlang.types.Type; +import com.compilerprogramming.ezlang.types.EZType; /** * Represents a Virtual Register in the abstract machine. @@ -44,7 +44,7 @@ public class Register { /** * The type of the register */ - public final Type type; + public final EZType type; /** * The location of this register relative to the base * of the executing function. Multiple registers may share the same @@ -52,10 +52,10 @@ public class Register { */ protected int frameSlot; - public Register(int id, String name, Type type) { + public Register(int id, String name, EZType type) { this(id,name,type,id); // Initially frame slot is set to the unique ID } - protected Register(int id, String name, Type type, int frameSlot) { + protected Register(int id, String name, EZType type, int frameSlot) { this.id = id; this.name = name; this.type = type; diff --git a/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/RegisterPool.java b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/RegisterPool.java index 88469af..9a0a77a 100644 --- a/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/RegisterPool.java +++ b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/RegisterPool.java @@ -1,6 +1,6 @@ package com.compilerprogramming.ezlang.compiler; -import com.compilerprogramming.ezlang.types.Type; +import com.compilerprogramming.ezlang.types.EZType; import java.util.ArrayList; @@ -18,20 +18,20 @@ public class RegisterPool { public Register getReg(int regNumber) { return registers.get(regNumber); } - public Register newReg(String baseName, Type type) { + public Register newReg(String baseName, EZType type) { var id = registers.size(); var reg = new Register(id, baseName, type); registers.add(reg); return reg; } - public Register newTempReg(Type type) { + public Register newTempReg(EZType type) { var id = registers.size(); var name = "%t"+id; var reg = new Register(id, name, type); registers.add(reg); return reg; } - public Register newTempReg(String baseName, Type type) { + public Register newTempReg(String baseName, EZType type) { var id = registers.size(); var name = baseName+"_"+id; var reg = new Register(id, name, type); diff --git a/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/SparseConditionalConstantPropagation.java b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/SparseConditionalConstantPropagation.java index 36edb74..ba96971 100644 --- a/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/SparseConditionalConstantPropagation.java +++ b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/SparseConditionalConstantPropagation.java @@ -1,7 +1,7 @@ package com.compilerprogramming.ezlang.compiler; import com.compilerprogramming.ezlang.exceptions.CompilerException; -import com.compilerprogramming.ezlang.types.Type; +import com.compilerprogramming.ezlang.types.EZType; import java.util.*; @@ -361,7 +361,7 @@ private boolean evalInstruction(Instruction instruction) { } else throw new IllegalStateException(); } case Instruction.Call callInst -> { - if (!(callInst.callee.returnType instanceof Type.TypeVoid)) { + if (!(callInst.callee.returnType instanceof EZType.EZTypeVoid)) { var cell = valueLattice.get(callInst.returnOperand().reg); changed = cell.setKind(V_VARYING); } diff --git a/optvm/src/main/java/com/compilerprogramming/ezlang/interpreter/Interpreter.java b/optvm/src/main/java/com/compilerprogramming/ezlang/interpreter/Interpreter.java index 654d2df..31912dc 100644 --- a/optvm/src/main/java/com/compilerprogramming/ezlang/interpreter/Interpreter.java +++ b/optvm/src/main/java/com/compilerprogramming/ezlang/interpreter/Interpreter.java @@ -7,7 +7,7 @@ import com.compilerprogramming.ezlang.exceptions.CompilerException; import com.compilerprogramming.ezlang.exceptions.InterpreterException; import com.compilerprogramming.ezlang.types.Symbol; -import com.compilerprogramming.ezlang.types.Type; +import com.compilerprogramming.ezlang.types.EZType; import com.compilerprogramming.ezlang.types.TypeDictionary; public class Interpreter { @@ -122,7 +122,7 @@ else if (arg instanceof Operand.NullConstantOperand) { Frame newFrame = new Frame(frame, baseReg, callInst.callee); interpret(execStack, newFrame); // Copy return value in expected location - if (!(callInst.callee.returnType instanceof Type.TypeVoid)) { + if (!(callInst.callee.returnType instanceof EZType.EZTypeVoid)) { execStack.stack[base + callInst.returnOperand().frameSlot()] = execStack.stack[baseReg]; } } @@ -302,7 +302,7 @@ public Frame(Symbol.FunctionTypeSymbol functionSymbol) { this.bytecodeFunction = (CompiledFunction) functionSymbol.code(); } - Frame(Frame caller, int base, Type.TypeFunction functionType) { + Frame(Frame caller, int base, EZType.EZTypeFunction functionType) { this.caller = caller; this.base = base; this.bytecodeFunction = (CompiledFunction) functionType.code; diff --git a/optvm/src/main/java/com/compilerprogramming/ezlang/interpreter/Value.java b/optvm/src/main/java/com/compilerprogramming/ezlang/interpreter/Value.java index 6717daa..fc46c3b 100644 --- a/optvm/src/main/java/com/compilerprogramming/ezlang/interpreter/Value.java +++ b/optvm/src/main/java/com/compilerprogramming/ezlang/interpreter/Value.java @@ -1,6 +1,6 @@ package com.compilerprogramming.ezlang.interpreter; -import com.compilerprogramming.ezlang.types.Type; +import com.compilerprogramming.ezlang.types.EZType; import java.util.ArrayList; @@ -15,9 +15,9 @@ static public class NullValue extends Value { public NullValue() {} } static public class ArrayValue extends Value { - public final Type.TypeArray arrayType; + public final EZType.EZTypeArray arrayType; public final ArrayList values; - public ArrayValue(Type.TypeArray arrayType, long len, Value initValue) { + public ArrayValue(EZType.EZTypeArray arrayType, long len, Value initValue) { this.arrayType = arrayType; values = new ArrayList<>(); for (long i = 0; i < len; i++) { @@ -26,9 +26,9 @@ public ArrayValue(Type.TypeArray arrayType, long len, Value initValue) { } } static public class StructValue extends Value { - public final Type.TypeStruct structType; + public final EZType.EZTypeStruct structType; public final Value[] fields; - public StructValue(Type.TypeStruct structType) { + public StructValue(EZType.EZTypeStruct structType) { this.structType = structType; this.fields = new Value[structType.numFields()]; } diff --git a/optvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestInterferenceGraph.java b/optvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestInterferenceGraph.java index 8018cba..e20846f 100644 --- a/optvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestInterferenceGraph.java +++ b/optvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestInterferenceGraph.java @@ -1,7 +1,7 @@ package com.compilerprogramming.ezlang.compiler; import com.compilerprogramming.ezlang.types.Symbol; -import com.compilerprogramming.ezlang.types.Type; +import com.compilerprogramming.ezlang.types.EZType; import com.compilerprogramming.ezlang.types.TypeDictionary; import org.junit.Assert; import org.junit.Test; @@ -10,7 +10,7 @@ public class TestInterferenceGraph { private CompiledFunction buildTest1() { TypeDictionary typeDictionary = new TypeDictionary(); - Type.TypeFunction functionType = new Type.TypeFunction("foo"); + EZType.EZTypeFunction functionType = new EZType.EZTypeFunction("foo"); var argSymbol = new Symbol.ParameterSymbol("a", typeDictionary.INT); functionType.addArg(argSymbol); functionType.setReturnType(typeDictionary.INT); @@ -81,7 +81,7 @@ public void test1() { */ private CompiledFunction buildTest2() { TypeDictionary typeDictionary = new TypeDictionary(); - Type.TypeFunction functionType = new Type.TypeFunction("foo"); + EZType.EZTypeFunction functionType = new EZType.EZTypeFunction("foo"); functionType.setReturnType(typeDictionary.VOID); CompiledFunction function = new CompiledFunction(functionType, typeDictionary); RegisterPool regPool = function.registerPool; @@ -159,7 +159,7 @@ public void test3() { /* Test move does not interfere with uses */ public static CompiledFunction buildTest4() { TypeDictionary typeDictionary = new TypeDictionary(); - Type.TypeFunction functionType = new Type.TypeFunction("foo"); + EZType.EZTypeFunction functionType = new EZType.EZTypeFunction("foo"); functionType.setReturnType(typeDictionary.VOID); CompiledFunction function = new CompiledFunction(functionType, typeDictionary); RegisterPool regPool = function.registerPool; diff --git a/optvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestLiveness.java b/optvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestLiveness.java index 7a324b2..94c95e6 100644 --- a/optvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestLiveness.java +++ b/optvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestLiveness.java @@ -1,7 +1,7 @@ package com.compilerprogramming.ezlang.compiler; import com.compilerprogramming.ezlang.types.Symbol; -import com.compilerprogramming.ezlang.types.Type; +import com.compilerprogramming.ezlang.types.EZType; import com.compilerprogramming.ezlang.types.TypeDictionary; import org.junit.Assert; import org.junit.Test; @@ -245,7 +245,7 @@ func foo(a: Int,b: Int) /* page 448 Engineering a Compiler */ static CompiledFunction buildTest3() { TypeDictionary typeDictionary = new TypeDictionary(); - Type.TypeFunction functionType = new Type.TypeFunction("foo"); + EZType.EZTypeFunction functionType = new EZType.EZTypeFunction("foo"); functionType.setReturnType(typeDictionary.INT); CompiledFunction function = new CompiledFunction(functionType, typeDictionary); RegisterPool regPool = function.registerPool; diff --git a/optvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestSSATransform.java b/optvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestSSATransform.java index 8897512..5e926e3 100644 --- a/optvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestSSATransform.java +++ b/optvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestSSATransform.java @@ -1,10 +1,9 @@ package com.compilerprogramming.ezlang.compiler; import com.compilerprogramming.ezlang.types.Symbol; -import com.compilerprogramming.ezlang.types.Type; +import com.compilerprogramming.ezlang.types.EZType; import com.compilerprogramming.ezlang.types.TypeDictionary; import org.junit.Assert; -import org.junit.Ignore; import org.junit.Test; import java.util.Arrays; @@ -628,7 +627,7 @@ func bar(arg: Int)->Int { */ static CompiledFunction buildLostCopyTest() { TypeDictionary typeDictionary = new TypeDictionary(); - Type.TypeFunction functionType = new Type.TypeFunction("foo"); + EZType.EZTypeFunction functionType = new EZType.EZTypeFunction("foo"); var argSymbol = new Symbol.ParameterSymbol("p", typeDictionary.INT); functionType.addArg(argSymbol); functionType.setReturnType(typeDictionary.INT); @@ -699,7 +698,7 @@ public void testLostCopyProblem() { */ static CompiledFunction buildSwapTest() { TypeDictionary typeDictionary = new TypeDictionary(); - Type.TypeFunction functionType = new Type.TypeFunction("foo"); + EZType.EZTypeFunction functionType = new EZType.EZTypeFunction("foo"); var argSymbol = new Symbol.ParameterSymbol("p", typeDictionary.INT); functionType.addArg(argSymbol); functionType.setReturnType(typeDictionary.VOID); diff --git a/parser/src/main/java/com/compilerprogramming/ezlang/parser/AST.java b/parser/src/main/java/com/compilerprogramming/ezlang/parser/AST.java index 162dd29..8bd6020 100644 --- a/parser/src/main/java/com/compilerprogramming/ezlang/parser/AST.java +++ b/parser/src/main/java/com/compilerprogramming/ezlang/parser/AST.java @@ -3,7 +3,7 @@ import com.compilerprogramming.ezlang.lexer.Token; import com.compilerprogramming.ezlang.types.Scope; import com.compilerprogramming.ezlang.types.Symbol; -import com.compilerprogramming.ezlang.types.Type; +import com.compilerprogramming.ezlang.types.EZType; import java.util.ArrayList; import java.util.List; @@ -162,7 +162,7 @@ public void accept(ASTVisitor visitor) { } public abstract static class Expr extends AST { - public Type type; + public EZType type; } public abstract static class TypeExpr extends Expr { diff --git a/registervm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java b/registervm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java index 3071909..936ab2b 100644 --- a/registervm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java +++ b/registervm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java @@ -4,7 +4,7 @@ import com.compilerprogramming.ezlang.parser.AST; import com.compilerprogramming.ezlang.types.Scope; import com.compilerprogramming.ezlang.types.Symbol; -import com.compilerprogramming.ezlang.types.Type; +import com.compilerprogramming.ezlang.types.EZType; import com.compilerprogramming.ezlang.types.TypeDictionary; import java.util.ArrayList; @@ -281,7 +281,7 @@ private boolean compileExpr(AST.Expr expr) { private boolean compileCallExpr(AST.CallExpr callExpr) { compileExpr(callExpr.callee); var callee = pop(); - Type.TypeFunction calleeType = null; + EZType.EZTypeFunction calleeType = null; if (callee instanceof Operand.LocalFunctionOperand functionOperand) calleeType = functionOperand.functionType; else throw new CompilerException("Cannot call a non function type"); @@ -303,8 +303,8 @@ private boolean compileCallExpr(AST.CallExpr callExpr) { for (int i = 0; i < args.size(); i++) pop(); Operand.TempRegisterOperand ret = null; - if (callExpr.callee.type instanceof Type.TypeFunction tf && - !(tf.returnType instanceof Type.TypeVoid)) { + if (callExpr.callee.type instanceof EZType.EZTypeFunction tf && + !(tf.returnType instanceof EZType.EZTypeVoid)) { ret = createTemp(tf.returnType); assert ret.regnum-maxLocalReg == returnStackPos; } @@ -312,12 +312,12 @@ private boolean compileCallExpr(AST.CallExpr callExpr) { return false; } - private Type.TypeStruct getStructType(Type t) { - if (t instanceof Type.TypeStruct typeStruct) { + private EZType.EZTypeStruct getStructType(EZType t) { + if (t instanceof EZType.EZTypeStruct typeStruct) { return typeStruct; } - else if (t instanceof Type.TypeNullable ptr && - ptr.baseType instanceof Type.TypeStruct typeStruct) { + else if (t instanceof EZType.EZTypeNullable ptr && + ptr.baseType instanceof EZType.EZTypeStruct typeStruct) { return typeStruct; } else @@ -325,7 +325,7 @@ else if (t instanceof Type.TypeNullable ptr && } private boolean compileFieldExpr(AST.GetFieldExpr fieldExpr) { - Type.TypeStruct typeStruct = getStructType(fieldExpr.object.type); + EZType.EZTypeStruct typeStruct = getStructType(fieldExpr.object.type); int fieldIndex = typeStruct.getFieldIndex(fieldExpr.fieldName); if (fieldIndex < 0) throw new CompilerException("Field " + fieldExpr.fieldName + " not found"); @@ -348,7 +348,7 @@ private boolean compileArrayIndexExpr(AST.ArrayLoadExpr arrayIndexExpr) { } private boolean compileSetFieldExpr(AST.SetFieldExpr setFieldExpr) { - Type.TypeStruct structType = (Type.TypeStruct) setFieldExpr.object.type; + EZType.EZTypeStruct structType = (EZType.EZTypeStruct) setFieldExpr.object.type; int fieldIndex = structType.getFieldIndex(setFieldExpr.fieldName); if (fieldIndex == -1) throw new CompilerException("Field " + setFieldExpr.fieldName + " not found in struct " + structType.name); @@ -398,7 +398,7 @@ private boolean compileInitExpr(AST.InitExpr initExpr) { } private boolean compileSymbolExpr(AST.NameExpr symbolExpr) { - if (symbolExpr.type instanceof Type.TypeFunction functionType) + if (symbolExpr.type instanceof EZType.EZTypeFunction functionType) pushOperand(new Operand.LocalFunctionOperand(functionType)); else { Symbol.VarSymbol varSymbol = (Symbol.VarSymbol) symbolExpr.symbol; @@ -506,23 +506,23 @@ private boolean compileUnaryExpr(AST.UnaryExpr unaryExpr) { } private boolean compileConstantExpr(AST.LiteralExpr constantExpr) { - if (constantExpr.type instanceof Type.TypeInteger) + if (constantExpr.type instanceof EZType.EZTypeInteger) pushConstant(constantExpr.value.num.intValue(), constantExpr.type); - else if (constantExpr.type instanceof Type.TypeNull) + else if (constantExpr.type instanceof EZType.EZTypeNull) pushNullConstant(constantExpr.type); else throw new CompilerException("Invalid constant type"); return false; } - private void pushConstant(long value, Type type) { + private void pushConstant(long value, EZType type) { pushOperand(new Operand.ConstantOperand(value, type)); } - private void pushNullConstant(Type type) { + private void pushNullConstant(EZType type) { pushOperand(new Operand.NullConstantOperand(type)); } - private Operand.TempRegisterOperand createTemp(Type type) { + private Operand.TempRegisterOperand createTemp(EZType type) { var tempRegister = new Operand.TempRegisterOperand(virtualStack.size()+maxLocalReg, type); pushOperand(tempRegister); if (maxStackSize < virtualStack.size()) @@ -530,7 +530,7 @@ private Operand.TempRegisterOperand createTemp(Type type) { return tempRegister; } - Type typeOfOperand(Operand operand) { + EZType typeOfOperand(Operand operand) { if (operand instanceof Operand.ConstantOperand constant) return constant.type; else if (operand instanceof Operand.NullConstantOperand nullConstantOperand) @@ -541,7 +541,7 @@ else if (operand instanceof Operand.RegisterOperand registerOperand) } private Operand.TempRegisterOperand createTempAndMove(Operand src) { - Type type = typeOfOperand(src); + EZType type = typeOfOperand(src); var temp = createTemp(type); code(new Instruction.Move(src, temp)); return temp; @@ -603,10 +603,10 @@ else if (indexed instanceof Operand.LoadFieldOperand loadFieldOperand) code(new Instruction.Move(value, indexed)); } - private void codeNew(Type type, AST.Expr len, AST.Expr initVal) { - if (type instanceof Type.TypeArray typeArray) + private void codeNew(EZType type, AST.Expr len, AST.Expr initVal) { + if (type instanceof EZType.EZTypeArray typeArray) codeNewArray(typeArray, len, initVal); - else if (type instanceof Type.TypeStruct typeStruct) { + else if (type instanceof EZType.EZTypeStruct typeStruct) { var temp = createTemp(type); code(new Instruction.NewStruct(typeStruct, temp)); } @@ -614,7 +614,7 @@ else if (type instanceof Type.TypeStruct typeStruct) { throw new CompilerException("Unexpected type: " + type); } - private void codeNewArray(Type.TypeArray typeArray, AST.Expr len, AST.Expr initVal) { + private void codeNewArray(EZType.EZTypeArray typeArray, AST.Expr len, AST.Expr initVal) { var temp = createTemp(typeArray); Operand lenOperand = null; Operand initValOperand = null; diff --git a/registervm/src/main/java/com/compilerprogramming/ezlang/compiler/Compiler.java b/registervm/src/main/java/com/compilerprogramming/ezlang/compiler/Compiler.java index 37eaea0..d76569b 100644 --- a/registervm/src/main/java/com/compilerprogramming/ezlang/compiler/Compiler.java +++ b/registervm/src/main/java/com/compilerprogramming/ezlang/compiler/Compiler.java @@ -5,7 +5,7 @@ import com.compilerprogramming.ezlang.semantic.SemaAssignTypes; import com.compilerprogramming.ezlang.semantic.SemaDefineTypes; import com.compilerprogramming.ezlang.types.Symbol; -import com.compilerprogramming.ezlang.types.Type; +import com.compilerprogramming.ezlang.types.EZType; import com.compilerprogramming.ezlang.types.TypeDictionary; import java.util.BitSet; @@ -15,7 +15,7 @@ public class Compiler { private void compile(TypeDictionary typeDictionary) { for (Symbol symbol: typeDictionary.getLocalSymbols()) { if (symbol instanceof Symbol.FunctionTypeSymbol functionSymbol) { - Type.TypeFunction functionType = (Type.TypeFunction) functionSymbol.type; + EZType.EZTypeFunction functionType = (EZType.EZTypeFunction) functionSymbol.type; functionType.code = new CompiledFunction(functionSymbol, typeDictionary); } } diff --git a/registervm/src/main/java/com/compilerprogramming/ezlang/compiler/Instruction.java b/registervm/src/main/java/com/compilerprogramming/ezlang/compiler/Instruction.java index 73b5673..2386dbd 100644 --- a/registervm/src/main/java/com/compilerprogramming/ezlang/compiler/Instruction.java +++ b/registervm/src/main/java/com/compilerprogramming/ezlang/compiler/Instruction.java @@ -1,6 +1,6 @@ package com.compilerprogramming.ezlang.compiler; -import com.compilerprogramming.ezlang.types.Type; +import com.compilerprogramming.ezlang.types.EZType; public abstract class Instruction { @@ -57,16 +57,16 @@ public StringBuilder toStr(StringBuilder sb) { } public static class NewArray extends Instruction { - public final Type.TypeArray type; - public NewArray(Type.TypeArray type, Operand.RegisterOperand destOperand) { + public final EZType.EZTypeArray type; + public NewArray(EZType.EZTypeArray type, Operand.RegisterOperand destOperand) { super(I_NEW_ARRAY, destOperand); this.type = type; } - public NewArray(Type.TypeArray type, Operand.RegisterOperand destOperand, Operand len) { + public NewArray(EZType.EZTypeArray type, Operand.RegisterOperand destOperand, Operand len) { super(I_NEW_ARRAY, destOperand, len); this.type = type; } - public NewArray(Type.TypeArray type, Operand.RegisterOperand destOperand, Operand len, Operand initValue) { + public NewArray(EZType.EZTypeArray type, Operand.RegisterOperand destOperand, Operand len, Operand initValue) { super(I_NEW_ARRAY, destOperand, len, initValue); this.type = type; } @@ -88,8 +88,8 @@ public StringBuilder toStr(StringBuilder sb) { } public static class NewStruct extends Instruction { - public final Type.TypeStruct type; - public NewStruct(Type.TypeStruct type, Operand.RegisterOperand destOperand) { + public final EZType.EZTypeStruct type; + public NewStruct(EZType.EZTypeStruct type, Operand.RegisterOperand destOperand) { super(I_NEW_STRUCT, destOperand); this.type = type; } @@ -244,9 +244,9 @@ public StringBuilder toStr(StringBuilder sb) { } public static class Call extends Instruction { - public final Type.TypeFunction callee; + public final EZType.EZTypeFunction callee; public final int newbase; - public Call(int newbase, Operand.RegisterOperand returnOperand, Type.TypeFunction callee, Operand.RegisterOperand... args) { + public Call(int newbase, Operand.RegisterOperand returnOperand, EZType.EZTypeFunction callee, Operand.RegisterOperand... args) { super(I_CALL, returnOperand, args); this.callee = callee; this.newbase = newbase; diff --git a/registervm/src/main/java/com/compilerprogramming/ezlang/compiler/Operand.java b/registervm/src/main/java/com/compilerprogramming/ezlang/compiler/Operand.java index 54188da..d2315f3 100644 --- a/registervm/src/main/java/com/compilerprogramming/ezlang/compiler/Operand.java +++ b/registervm/src/main/java/com/compilerprogramming/ezlang/compiler/Operand.java @@ -1,14 +1,14 @@ package com.compilerprogramming.ezlang.compiler; -import com.compilerprogramming.ezlang.types.Type; +import com.compilerprogramming.ezlang.types.EZType; public class Operand { - Type type; + EZType type; public static class ConstantOperand extends Operand { public final long value; - public ConstantOperand(long value, Type type) { + public ConstantOperand(long value, EZType type) { this.value = value; this.type = type; } @@ -19,7 +19,7 @@ public String toString() { } public static class NullConstantOperand extends Operand { - public NullConstantOperand(Type type) { + public NullConstantOperand(EZType type) { this.type = type; } @Override @@ -49,8 +49,8 @@ public String toString() { } public static class LocalFunctionOperand extends Operand { - public final Type.TypeFunction functionType; - public LocalFunctionOperand(Type.TypeFunction functionType) { + public final EZType.EZTypeFunction functionType; + public LocalFunctionOperand(EZType.EZTypeFunction functionType) { this.functionType = functionType; } @Override @@ -65,7 +65,7 @@ public String toString() { * register number from start of temp area. */ public static class TempRegisterOperand extends RegisterOperand { - public TempRegisterOperand(int regnum, Type type) { + public TempRegisterOperand(int regnum, EZType type) { super(regnum); this.type = type; } diff --git a/registervm/src/main/java/com/compilerprogramming/ezlang/interpreter/Interpreter.java b/registervm/src/main/java/com/compilerprogramming/ezlang/interpreter/Interpreter.java index f441455..62f7411 100644 --- a/registervm/src/main/java/com/compilerprogramming/ezlang/interpreter/Interpreter.java +++ b/registervm/src/main/java/com/compilerprogramming/ezlang/interpreter/Interpreter.java @@ -7,7 +7,7 @@ import com.compilerprogramming.ezlang.exceptions.CompilerException; import com.compilerprogramming.ezlang.exceptions.InterpreterException; import com.compilerprogramming.ezlang.types.Symbol; -import com.compilerprogramming.ezlang.types.Type; +import com.compilerprogramming.ezlang.types.EZType; import com.compilerprogramming.ezlang.types.TypeDictionary; public class Interpreter { @@ -122,7 +122,7 @@ else if (arg instanceof Operand.NullConstantOperand) { Frame newFrame = new Frame(frame, baseReg, callInst.callee); interpret(execStack, newFrame); // Copy return value in expected location - if (!(callInst.callee.returnType instanceof Type.TypeVoid)) { + if (!(callInst.callee.returnType instanceof EZType.EZTypeVoid)) { execStack.stack[base + callInst.returnOperand().frameSlot()] = execStack.stack[baseReg]; } } @@ -301,7 +301,7 @@ public Frame(Symbol.FunctionTypeSymbol functionSymbol) { this.bytecodeFunction = (CompiledFunction) functionSymbol.code(); } - Frame(Frame caller, int base, Type.TypeFunction functionType) { + Frame(Frame caller, int base, EZType.EZTypeFunction functionType) { this.caller = caller; this.base = base; this.bytecodeFunction = (CompiledFunction) functionType.code; diff --git a/registervm/src/main/java/com/compilerprogramming/ezlang/interpreter/Value.java b/registervm/src/main/java/com/compilerprogramming/ezlang/interpreter/Value.java index 6717daa..fc46c3b 100644 --- a/registervm/src/main/java/com/compilerprogramming/ezlang/interpreter/Value.java +++ b/registervm/src/main/java/com/compilerprogramming/ezlang/interpreter/Value.java @@ -1,6 +1,6 @@ package com.compilerprogramming.ezlang.interpreter; -import com.compilerprogramming.ezlang.types.Type; +import com.compilerprogramming.ezlang.types.EZType; import java.util.ArrayList; @@ -15,9 +15,9 @@ static public class NullValue extends Value { public NullValue() {} } static public class ArrayValue extends Value { - public final Type.TypeArray arrayType; + public final EZType.EZTypeArray arrayType; public final ArrayList values; - public ArrayValue(Type.TypeArray arrayType, long len, Value initValue) { + public ArrayValue(EZType.EZTypeArray arrayType, long len, Value initValue) { this.arrayType = arrayType; values = new ArrayList<>(); for (long i = 0; i < len; i++) { @@ -26,9 +26,9 @@ public ArrayValue(Type.TypeArray arrayType, long len, Value initValue) { } } static public class StructValue extends Value { - public final Type.TypeStruct structType; + public final EZType.EZTypeStruct structType; public final Value[] fields; - public StructValue(Type.TypeStruct structType) { + public StructValue(EZType.EZTypeStruct structType) { this.structType = structType; this.fields = new Value[structType.numFields()]; } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/Compiler.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/Compiler.java index 3d7e546..bf45445 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/Compiler.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/Compiler.java @@ -12,7 +12,7 @@ import com.compilerprogramming.ezlang.semantic.SemaDefineTypes; import com.compilerprogramming.ezlang.types.Scope; import com.compilerprogramming.ezlang.types.Symbol; -import com.compilerprogramming.ezlang.types.Type; +import com.compilerprogramming.ezlang.types.EZType; import com.compilerprogramming.ezlang.types.TypeDictionary; import java.util.ArrayList; @@ -57,22 +57,22 @@ public class Compiler { // Mapping from a type name to a Type. The string name matches // `type.str()` call. No TypeMemPtrs are in here, because Simple does not // have C-style '*ptr' references. - public static HashMap TYPES = new HashMap<>(); + public static HashMap TYPES = new HashMap<>(); private ArrayList ctorStack = new ArrayList<>(); - public Compiler(CodeGen codeGen, SONTypeInteger arg) { + public Compiler(CodeGen codeGen, TypeInteger arg) { this._code = codeGen; } public void parse() { this.typeDictionary = createAST(_code._src); - Map types = new HashMap<>(); + Map types = new HashMap<>(); populateDefaultTypes(types); populateTypes(types); TYPES.putAll(types); - ZERO = con(SONTypeInteger.ZERO).keep(); - NIL = con(SONType.NIL).keep(); + ZERO = con(TypeInteger.ZERO).keep(); + NIL = con(Type.NIL).keep(); XCTRL= new XCtrlNode().peephole().keep(); processFunctions(); } @@ -89,26 +89,26 @@ public TypeDictionary createAST(String src) { } - private void populateDefaultTypes(Map types) { + private void populateDefaultTypes(Map types) { // Pre-create int, [int] and *[int] types - types.put(typeDictionary.INT.name(), SONTypeInteger.BOT); - var intArrayType = SONTypeStruct.makeAry(SONTypeInteger.U32, _code.getALIAS(), SONTypeInteger.BOT, _code.getALIAS()); - var ptrIntArrayType = SONTypeMemPtr.make(intArrayType); + types.put(typeDictionary.INT.name(), TypeInteger.BOT); + var intArrayType = TypeStruct.makeAry(TypeInteger.U32, _code.getALIAS(), TypeInteger.BOT, _code.getALIAS()); + var ptrIntArrayType = TypeMemPtr.make(intArrayType); types.put("[" + typeDictionary.INT.name() + "]", ptrIntArrayType); // Also get the types created by default - for (SONType t: SONType.gather()) { + for (Type t: Type.gather()) { types.put(t.str(), t); } } - private void populateTypes(Map structTypes) { + private void populateTypes(Map structTypes) { // First process struct types for (var symbol: typeDictionary.getLocalSymbols()) { if (symbol instanceof Symbol.TypeSymbol typeSymbol) { - if (typeSymbol.type instanceof Type.TypeStruct typeStruct) { + if (typeSymbol.type instanceof EZType.EZTypeStruct typeStruct) { createSONStructType(structTypes,typeSymbol.name, typeStruct); } - else if (typeSymbol.type instanceof Type.TypeArray typeArray) { + else if (typeSymbol.type instanceof EZType.EZTypeArray typeArray) { getSONType(structTypes, typeArray); } } @@ -129,33 +129,33 @@ private void processFunctions() { } } - private void createFunctionType(Map structTypes, Symbol.FunctionTypeSymbol functionSymbol) { - Type.TypeFunction functionType = (Type.TypeFunction) functionSymbol.type; - Ary params = new Ary<>(SONType.class); + private void createFunctionType(Map structTypes, Symbol.FunctionTypeSymbol functionSymbol) { + EZType.EZTypeFunction functionType = (EZType.EZTypeFunction) functionSymbol.type; + Ary params = new Ary<>(Type.class); for (var symbol: functionType.args) { if (symbol instanceof Symbol.ParameterSymbol parameterSymbol) { - SONType paramType = getSONType(structTypes, parameterSymbol.type); + Type paramType = getSONType(structTypes, parameterSymbol.type); params.push(paramType); } } var retType = getSONType(structTypes, functionType.returnType); - SONTypeFunPtr tfp = _code.makeFun2(new SONTypeTuple(params.asAry()),retType); + TypeFunPtr tfp = _code.makeFun2(new TypeTuple(params.asAry()),retType); structTypes.put(functionSymbol.name, tfp); } - private void createSONStructType(Map structTypes, String typeName, Type.TypeStruct typeStruct) { + private void createSONStructType(Map structTypes, String typeName, EZType.EZTypeStruct typeStruct) { Ary fs = new Ary<>(Field.class); for (int i = 0; i < typeStruct.numFields(); i++) { String name = typeStruct.getFieldName(i); - Type type = typeStruct.getField(name); // FIXME + EZType type = typeStruct.getField(name); // FIXME fs.push(new Field(name,getSONType(structTypes,type),_code.getALIAS(),false)); } // A Struct type may have been created before because of // reference from itself; in which case we need to update that - SONType fref = structTypes.get(typeName); + Type fref = structTypes.get(typeName); if (fref != null) { - if (fref instanceof SONTypeMemPtr ptr && - ptr._obj instanceof SONTypeStruct ts) { + if (fref instanceof TypeMemPtr ptr && + ptr._obj instanceof TypeStruct ts) { assert ts._fields.length == 0; // Add the fields to the existing type ts._fields = fs.asAry(); @@ -163,73 +163,73 @@ private void createSONStructType(Map structTypes, String typeNa else throw new CompilerException("Expected struct type " + typeName + " but got " + fref); } else { - var ts = SONTypeStruct.make(typeName, fs.asAry()); - var ptr = SONTypeMemPtr.make((byte)2,ts); + var ts = TypeStruct.make(typeName, fs.asAry()); + var ptr = TypeMemPtr.make((byte)2,ts); structTypes.put(typeName,ptr); } } - private String getSONTypeName(Type type) { - if (type instanceof Type.TypeFunction typeFunction) { + private String getSONTypeName(EZType type) { + if (type instanceof EZType.EZTypeFunction typeFunction) { return typeFunction.name; } - else if (type instanceof Type.TypeArray typeArray) { + else if (type instanceof EZType.EZTypeArray typeArray) { return "*[" + getSONTypeName(typeArray.getElementType()) + "]"; } - else if (type instanceof Type.TypeStruct typeStruct) { + else if (type instanceof EZType.EZTypeStruct typeStruct) { return "*" + typeStruct.name; } - else if (type instanceof Type.TypeInteger || - type instanceof Type.TypeVoid) { - return SONTypeInteger.BOT.str(); + else if (type instanceof EZType.EZTypeInteger || + type instanceof EZType.EZTypeVoid) { + return TypeInteger.BOT.str(); } - else if (type instanceof Type.TypeNull) { - return SONTypeNil.NIL.str(); + else if (type instanceof EZType.EZTypeNull) { + return TypeNil.NIL.str(); } - else if (type instanceof Type.TypeNullable typeNullable) { + else if (type instanceof EZType.EZTypeNullable typeNullable) { return getSONTypeName(typeNullable.baseType)+"?"; } else throw new CompilerException("Not yet implemented " + type.name()); } - private SONType getSONType(Map structTypes, Type type) { - SONType t = structTypes.get(type.name()); + private Type getSONType(Map structTypes, EZType type) { + Type t = structTypes.get(type.name()); if (t != null) return t; - if (type instanceof Type.TypeStruct) { + if (type instanceof EZType.EZTypeStruct) { // For struct types in EeZee language a reference // to T means *T in SoN // Create SON struct type - SONTypeStruct ts = SONTypeStruct.make(type.name, new Field[0]); + TypeStruct ts = TypeStruct.make(type.name, new Field[0]); // Now create *T - SONTypeMemPtr ptr = SONTypeMemPtr.make((byte)2,ts); + TypeMemPtr ptr = TypeMemPtr.make((byte)2,ts); // EeZee T maps to SoN *T structTypes.put(type.name(), ptr); return ptr; } - else if (type instanceof Type.TypeArray typeArray) { + else if (type instanceof EZType.EZTypeArray typeArray) { // A reference to array in EeZee means // *array in SoN - SONType elementType = getSONType(structTypes,typeArray.getElementType()); - SONTypeStruct ts = SONTypeStruct.makeArray(SONTypeInteger.U32, _code.getALIAS(), elementType, _code.getALIAS()); - SONTypeMemPtr ptr = SONTypeMemPtr.make((byte)2,ts); + Type elementType = getSONType(structTypes,typeArray.getElementType()); + TypeStruct ts = TypeStruct.makeArray(TypeInteger.U32, _code.getALIAS(), elementType, _code.getALIAS()); + TypeMemPtr ptr = TypeMemPtr.make((byte)2,ts); structTypes.put(typeArray.name(), ptr); // Array type name is not same as ptr str() return ptr; } - else if (type instanceof Type.TypeNullable typeNullable) { - SONType baseType = getSONType(structTypes,typeNullable.baseType); - SONTypeMemPtr ptr = null; - if (baseType instanceof SONTypeMemPtr ptr1) { + else if (type instanceof EZType.EZTypeNullable typeNullable) { + Type baseType = getSONType(structTypes,typeNullable.baseType); + TypeMemPtr ptr = null; + if (baseType instanceof TypeMemPtr ptr1) { if (ptr1.nullable()) ptr = ptr1; else - ptr = SONTypeMemPtr.make((byte)3,ptr1._obj); + ptr = TypeMemPtr.make((byte)3,ptr1._obj); } else - ptr = SONTypeMemPtr.make((byte)2,(SONTypeStruct) baseType); + ptr = TypeMemPtr.make((byte)2,(TypeStruct) baseType); structTypes.put(typeNullable.name(), ptr); return ptr; } - else if (type instanceof Type.TypeVoid) { + else if (type instanceof EZType.EZTypeVoid) { return structTypes.get("Int"); // Only allowed in return types } throw new CompilerException("Count not find type " + type.name()); @@ -244,7 +244,7 @@ private void defineScopedVars(Scope scope, ScopeNode scopeNode, FunNode fun) { for (Symbol symbol: scope.getLocalSymbols()) { if (symbol instanceof Symbol.VarSymbol varSymbol) { varSymbol.regNumber = REGNUM++; - SONType sonType = TYPES.get(varSymbol.type.name()); + Type sonType = TYPES.get(varSymbol.type.name()); if (sonType == null) throw new CompilerException("Unknown SON Type "+varSymbol.type.name()); Node init = null; @@ -259,13 +259,13 @@ private void defineScopedVars(Scope scope, ScopeNode scopeNode, FunNode fun) { private void generateFunction(Symbol.FunctionTypeSymbol functionTypeSymbol) { _scope = new ScopeNode(); - _scope.define(ScopeNode.CTRL, SONType.CONTROL , false, null); - _scope.define(ScopeNode.MEM0, SONTypeMem.BOT , false, null); + _scope.define(ScopeNode.CTRL, Type.CONTROL , false, null); + _scope.define(ScopeNode.MEM0, TypeMem.BOT , false, null); ctrl(XCTRL); _scope.mem(new MemMergeNode(false)); - var funType = (SONTypeFunPtr) TYPES.get(functionTypeSymbol.name); + var funType = (TypeFunPtr) TYPES.get(functionTypeSymbol.name); if (funType == null) throw new CompilerException("Function " + functionTypeSymbol.name + " not found"); // Parse whole program, as-if function header "{ int arg -> body }" @@ -280,7 +280,7 @@ private void generateFunction(Symbol.FunctionTypeSymbol functionTypeSymbol) { // INITS.clear(); _code._stop.peephole(); // if( show ) showGraph(); - showGraph(); + //showGraph(); } /** @@ -295,7 +295,7 @@ Node showGraph() { /** * Parses a function body, assuming the header is parsed. */ - private ReturnNode generateFunctionBody(Symbol.FunctionTypeSymbol functionTypeSymbol,SONTypeFunPtr sig) { + private ReturnNode generateFunctionBody(Symbol.FunctionTypeSymbol functionTypeSymbol, TypeFunPtr sig) { // Stack parser state on the local Java stack, and unstack it later Node oldctrl = ctrl().keep(); Node oldmem = _scope.mem().keep(); @@ -310,13 +310,13 @@ private ReturnNode generateFunctionBody(Symbol.FunctionTypeSymbol functionTypeSy // the exact single function). _code.link(fun); - Node rpc = new ParmNode("$rpc",0,SONTypeRPC.BOT,fun,con(SONTypeRPC.BOT)).peephole(); + Node rpc = new ParmNode("$rpc",0, TypeRPC.BOT,fun,con(TypeRPC.BOT)).peephole(); // Build a multi-exit return point for all function returns RegionNode r = new RegionNode(null,null).init(); assert r.inProgress(); - PhiNode rmem = new PhiNode(ScopeNode.MEM0,SONTypeMem.BOT,r,null).init(); - PhiNode rrez = new PhiNode(ScopeNode.ARG0,SONType.BOTTOM,r,null).init(); + PhiNode rmem = new PhiNode(ScopeNode.MEM0, TypeMem.BOT,r,null).init(); + PhiNode rrez = new PhiNode(ScopeNode.ARG0, Type.BOTTOM,r,null).init(); ReturnNode ret = new ReturnNode(r, rmem, rrez, rpc, fun).init(); fun.setRet(ret); assert ret.inProgress(); @@ -330,7 +330,7 @@ private ReturnNode generateFunctionBody(Symbol.FunctionTypeSymbol functionTypeSy // Private mem alias tracking per function MemMergeNode mem = new MemMergeNode(true); mem.addDef(null); // Alias#0 - mem.addDef(new ParmNode(ScopeNode.MEM0,1,SONTypeMem.BOT,fun,con(SONTypeMem.BOT)).peephole()); // All aliases + mem.addDef(new ParmNode(ScopeNode.MEM0,1, TypeMem.BOT,fun,con(TypeMem.BOT)).peephole()); // All aliases _scope.mem(mem); // All args, "as-if" called externally AST.FuncDecl funcDecl = (AST.FuncDecl) functionTypeSymbol.functionDecl; @@ -341,7 +341,7 @@ private ReturnNode generateFunctionBody(Symbol.FunctionTypeSymbol functionTypeSy Node last = compileStatement(funcDecl.block); // Last expression is the return - if( ctrl()._type==SONType.CONTROL ) + if( ctrl()._type== Type.CONTROL ) fun.addReturn(ctrl(), _scope.mem().merge(), last); // Pop off the inProgress node on the multi-exit Region merge @@ -411,15 +411,15 @@ private Node compileExpr(AST.Expr expr) { private Node compileFieldExpr(AST.GetFieldExpr getFieldExpr) { Node objPtr = compileExpr(getFieldExpr.object).keep(); // Sanity check expr for being a reference - if( !(objPtr._type instanceof SONTypeMemPtr ptr) ) { + if( !(objPtr._type instanceof TypeMemPtr ptr) ) { throw new CompilerException("Unexpected type " + objPtr._type.str()); } String name = getFieldExpr.fieldName; - SONTypeStruct base = ptr._obj; + TypeStruct base = ptr._obj; int fidx = base.find(name); if( fidx == -1 ) throw error("Accessing unknown field '" + name + "' from '" + ptr.str() + "'"); Field f = base._fields[fidx]; // Field from field index - SONType tf = f._type; + Type tf = f._type; // Field offset; fixed for structs Node off = con(base.offset(fidx)).keep(); Node load = new LoadNode(name, f._alias, tf, memAlias(f._alias), objPtr, off); @@ -439,16 +439,16 @@ private Node compileSetFieldExpr(AST.SetFieldExpr setFieldExpr) { else objPtr = compileExpr(setFieldExpr.object); // Sanity check expr for being a reference - if( !(objPtr._type instanceof SONTypeMemPtr ptr) ) { + if( !(objPtr._type instanceof TypeMemPtr ptr) ) { throw new CompilerException("Unexpected type " + objPtr._type.str()); } Node val = compileExpr(setFieldExpr.value).keep(); String name = setFieldExpr.fieldName; - SONTypeStruct base = ptr._obj; + TypeStruct base = ptr._obj; int fidx = base.find(name); if( fidx == -1 ) throw error("Accessing unknown field '" + name + "' from '" + ptr.str() + "'"); Field f = base._fields[fidx]; // Field from field index - SONType tf = f._type; + Type tf = f._type; Node mem = memAlias(f._alias); Node st = new StoreNode(f._fname,f._alias,tf,mem,objPtr,con(base.offset(fidx)),val.unkeep(),true).peephole(); memAlias(f._alias,st); @@ -458,17 +458,17 @@ private Node compileSetFieldExpr(AST.SetFieldExpr setFieldExpr) { private Node compileArrayIndexExpr(AST.ArrayLoadExpr arrayLoadExpr) { Node objPtr = compileExpr(arrayLoadExpr.array).keep(); // Sanity check expr for being a reference - if( !(objPtr._type instanceof SONTypeMemPtr ptr) ) { + if( !(objPtr._type instanceof TypeMemPtr ptr) ) { throw new CompilerException("Unexpected type " + objPtr._type.str()); } String name = "[]"; - SONTypeStruct base = ptr._obj; + TypeStruct base = ptr._obj; Node index = compileExpr(arrayLoadExpr.expr).keep(); Node off = peep(new AddNode(con(base.aryBase()),peep(new ShlNode(index.unkeep(),con(base.aryScale()))))).keep(); int fidx = base.find(name); if( fidx == -1 ) throw error("Accessing unknown field '" + name + "' from '" + ptr.str() + "'"); Field f = base._fields[fidx]; // Field from field index - SONType tf = f._type; + Type tf = f._type; Node load = new LoadNode(name, f._alias, tf, memAlias(f._alias), objPtr, off); // Arrays include control, as a proxy for a safety range check // Structs don't need this; they only need a NPE check which is @@ -487,18 +487,18 @@ private Node compileArrayStoreExpr(AST.ArrayStoreExpr arrayStoreExpr) { else objPtr = compileExpr(arrayStoreExpr.array); // Sanity check expr for being a reference - if( !(objPtr._type instanceof SONTypeMemPtr ptr) ) { + if( !(objPtr._type instanceof TypeMemPtr ptr) ) { throw new CompilerException("Unexpected type " + objPtr._type.str()); } String name = "[]"; - SONTypeStruct base = ptr._obj; + TypeStruct base = ptr._obj; Node index = compileExpr(arrayStoreExpr.expr).keep(); Node off = peep(new AddNode(con(base.aryBase()),peep(new ShlNode(index.unkeep(),con(base.aryScale()))))).keep(); Node val = compileExpr(arrayStoreExpr.value).keep(); int fidx = base.find(name); if( fidx == -1 ) throw error("Accessing unknown field '" + name + "' from '" + ptr.str() + "'"); Field f = base._fields[fidx]; // Field from field index - SONType tf = f._type; + Type tf = f._type; Node mem = memAlias(f._alias); Node st = new StoreNode(f._fname,f._alias,tf,mem,objPtr,off.unkeep(),val.unkeep(),true).peephole(); memAlias(f._alias,st); @@ -509,7 +509,7 @@ private Node compileInitExpr(AST.InitExpr initExpr) { Node objPtr = compileExpr(initExpr.newExpr).keep(); ctorStack.add(objPtr); // Sanity check expr for being a reference - if( !(objPtr._type instanceof SONTypeMemPtr ptr) ) { + if( !(objPtr._type instanceof TypeMemPtr ptr) ) { throw new CompilerException("Unexpected type " + objPtr._type.str()); } if (initExpr.initExprList != null && !initExpr.initExprList.isEmpty()) { @@ -521,7 +521,7 @@ private Node compileInitExpr(AST.InitExpr initExpr) { return objPtr.unkeep(); } - private Node newArray(SONTypeStruct ary, Node len) { + private Node newArray(TypeStruct ary, Node len) { int base = ary.aryBase (); int scale= ary.aryScale(); Node size = peep(new AddNode(con(base),peep(new ShlNode(len.keep(),con(scale))))); @@ -531,7 +531,7 @@ private Node newArray(SONTypeStruct ary, Node len) { * Return a NewNode initialized memory. * @param obj is the declared type, with GLB fields */ - private Node newStruct( SONTypeStruct obj, Node size) { + private Node newStruct(TypeStruct obj, Node size) { Field[] fs = obj._fields; if( fs==null ) throw error("Unknown struct type '" + obj._name + "'"); @@ -544,20 +544,20 @@ private Node newStruct( SONTypeStruct obj, Node size) { for( int i = 0; i < len; i++ ) ns[2+i] = memAlias(fs[i]._alias); // FIXME make - Node nnn = new NewNode(SONTypeMemPtr.make(obj), ns).peephole().keep(); + Node nnn = new NewNode(TypeMemPtr.make(obj), ns).peephole().keep(); for( int i = 0; i < len; i++ ) memAlias(fs[i]._alias, new ProjNode(nnn,i+2,memName(fs[i]._alias)).peephole()); return new ProjNode(nnn.unkeep(),1,obj._name).peephole(); } private Node compileNewExpr(AST.NewExpr newExpr) { - Type type = newExpr.type; - if (type instanceof Type.TypeArray typeArray) { - SONTypeMemPtr tarray = (SONTypeMemPtr) TYPES.get(typeArray.name()); + EZType type = newExpr.type; + if (type instanceof EZType.EZTypeArray typeArray) { + TypeMemPtr tarray = (TypeMemPtr) TYPES.get(typeArray.name()); return newArray(tarray._obj,newExpr.len==null?ZERO:compileExpr(newExpr.len)); } - else if (type instanceof Type.TypeStruct typeStruct) { - SONTypeMemPtr tptr = (SONTypeMemPtr) TYPES.get(typeStruct.name()); + else if (type instanceof EZType.EZTypeStruct typeStruct) { + TypeMemPtr tptr = (TypeMemPtr) TYPES.get(typeStruct.name()); return newStruct(tptr._obj,con(tptr._obj.offset(tptr._obj._fields.length))); } else @@ -625,15 +625,15 @@ private Node compileBinaryExpr(AST.BinaryExpr binaryExpr) { } private Node compileConstantExpr(AST.LiteralExpr constantExpr) { - if (constantExpr.type instanceof Type.TypeInteger) + if (constantExpr.type instanceof EZType.EZTypeInteger) return con(constantExpr.value.num.intValue()); - else if (constantExpr.type instanceof Type.TypeNull) + else if (constantExpr.type instanceof EZType.EZTypeNull) return NIL; else throw new CompilerException("Invalid constant type"); } private Node compileSymbolExpr(AST.NameExpr symbolExpr) { - if (symbolExpr.type instanceof Type.TypeFunction functionType) + if (symbolExpr.type instanceof EZType.EZTypeFunction functionType) return con(TYPES.get(functionType.name)); else { Symbol.VarSymbol varSymbol = (Symbol.VarSymbol) symbolExpr.symbol; @@ -653,10 +653,10 @@ private Node compileSymbolExpr(AST.NameExpr symbolExpr) { */ private Node compileCallExpr(AST.CallExpr callExpr) { Node expr = compileExpr(callExpr.callee); - if( expr._type == SONType.NIL ) + if( expr._type == Type.NIL ) throw error("Calling a null function pointer"); - if( !(expr instanceof FRefNode) && !expr._type.isa(SONTypeFunPtr.BOT) ) - throw error("Expected a function but got "+expr._type.glb().str()); + if( !(expr instanceof FRefNode) && !expr._type.isa(TypeFunPtr.BOT) ) + throw error("Expected a function but got "+expr._type.glb(false).str()); expr.keep(); // Keep while parsing args Ary args = new Ary(Node.class); @@ -674,11 +674,11 @@ private Node compileCallExpr(AST.CallExpr callExpr) { for( Node arg : args ) arg.unkeep(); // Dead into the call? Skip all the node gen - if( ctrl()._type == SONType.XCONTROL ) { + if( ctrl()._type == Type.XCONTROL ) { for( Node arg : args ) if( arg.isUnused() ) arg.kill(); - return con(SONType.TOP); + return con(Type.TOP); } // Into the call @@ -962,8 +962,8 @@ private Node compileBlock(AST.BlockStmt block) { return last; } - public static Node con(long con ) { return con==0 ? ZERO : con(SONTypeInteger.constant(con)); } - public static ConstantNode con( SONType t ) { return (ConstantNode)new ConstantNode(t).peephole(); } + public static Node con(long con ) { return con==0 ? ZERO : con(TypeInteger.constant(con)); } + public static ConstantNode con( Type t ) { return (ConstantNode)new ConstantNode(t).peephole(); } public Node peep( Node n ) { // Peephole, then improve with lexically scoped guards return _scope.upcastGuard(n.peephole()); diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/Var.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/Var.java index 6016939..65d82ee 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/Var.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/Var.java @@ -10,36 +10,32 @@ public class Var { public final String _name; // Declared name public int _idx; // index in containing scope - private SONType _type; // Declared type + private Type _type; // Declared type public boolean _final; // Final field public boolean _fref; // Forward ref - public Var(int idx, String name, SONType type, boolean xfinal) { + public Var(int idx, String name, Type type, boolean xfinal) { this(idx,name,type,xfinal,false); } - public Var(int idx, String name, SONType type, boolean xfinal, boolean fref) { + public Var(int idx, String name, Type type, boolean xfinal, boolean fref) { _idx = idx; _name = name; _type = type; _final = xfinal; _fref = fref; } - public SONType type() { + public Type type() { if( !_type.isFRef() ) return _type; // Update self to no longer use the forward ref type - SONType def = Compiler.TYPES.get(((SONTypeMemPtr)_type)._obj._name); + Type def = Compiler.TYPES.get(((TypeMemPtr)_type)._obj._name); return (_type=_type.meet(def)); } - public SONType lazyGLB() { - SONType t = type(); - return t instanceof SONTypeMemPtr ? t : t.glb(); - } // Forward reference variables (not types) must be BOTTOM and // distinct from inferred variables public boolean isFRef() { return _fref; } - public void defFRef(SONType type, boolean xfinal) { + public void defFRef(Type type, boolean xfinal) { assert isFRef() && xfinal; _type = type; _final = true; diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/BuildLRG.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/BuildLRG.java index 1b4f17b..195506b 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/BuildLRG.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/BuildLRG.java @@ -1,8 +1,7 @@ package com.compilerprogramming.ezlang.compiler.codegen; -import com.compilerprogramming.ezlang.compiler.Utils; import com.compilerprogramming.ezlang.compiler.nodes.*; -import com.compilerprogramming.ezlang.compiler.sontypes.SONTypeMem; +import com.compilerprogramming.ezlang.compiler.sontypes.TypeMem; abstract public class BuildLRG { // Compute live ranges in a single forwards pass. Every def is a new live @@ -17,7 +16,7 @@ abstract public class BuildLRG { public static boolean run(int round, RegAlloc alloc) { for( Node bb : alloc._code._cfg ) for( Node n : bb.outs() ) { - if( n instanceof PhiNode phi && !(phi._type instanceof SONTypeMem) ) { + if( n instanceof PhiNode phi && !(phi._type instanceof TypeMem) ) { // All Phi inputs end up with the same LRG. // Pass 1: find any pre-existing LRG, to avoid make-then-Union a LRG LRG lrg = alloc.lrg(phi); diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/CodeGen.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/CodeGen.java index fa890bd..e1dfe42 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/CodeGen.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/CodeGen.java @@ -23,7 +23,7 @@ public enum Phase { Opto, // Run ideal optimizations TypeCheck, // Last check for bad programs LoopTree, // Build a loop tree; break infinite loops - InstSelect, // Convert to target hardware nodes + Select, // Convert to target hardware nodes Schedule, // Global schedule (code motion) nodes LocalSched, // Local schedule RegAlloc, // Register allocation @@ -36,11 +36,11 @@ public enum Phase { // Compilation source code public final String _src; // Compile-time known initial argument type - public final SONTypeInteger _arg; + public final TypeInteger _arg; // --------------------------- - public CodeGen( String src ) { this(src, SONTypeInteger.BOT, 123L ); } - public CodeGen( String src, SONTypeInteger arg, long workListSeed ) { + public CodeGen( String src ) { this(src, TypeInteger.BOT, 123L ); } + public CodeGen( String src, TypeInteger arg, long workListSeed ) { CODE = this; _phase = null; _callingConv = null; @@ -57,14 +57,15 @@ public CodeGen( String src, SONTypeInteger arg, long workListSeed ) { public CodeGen driver( Phase phase ) { return driver(phase,null,null); } public CodeGen driver( Phase phase, String cpu, String callingConv ) { if( _phase==null ) parse(); - if( _phase.ordinal() < phase.ordinal() ) opto(); - if( _phase.ordinal() < phase.ordinal() ) typeCheck(); - if( _phase.ordinal() < phase.ordinal() ) loopTree(); - if( _phase.ordinal() < phase.ordinal() && cpu != null ) instSelect(cpu,callingConv); - if( _phase.ordinal() < phase.ordinal() ) GCM(); - if( _phase.ordinal() < phase.ordinal() ) localSched(); - if( _phase.ordinal() < phase.ordinal() ) regAlloc(); - if( _phase.ordinal() < phase.ordinal() ) encode(); + int p1 = phase.ordinal(); + if( _phase.ordinal() < p1 && _phase.ordinal() < Phase.Opto .ordinal() ) opto(); + if( _phase.ordinal() < p1 && _phase.ordinal() < Phase.TypeCheck .ordinal() ) typeCheck(); + if( _phase.ordinal() < p1 && _phase.ordinal() < Phase.LoopTree .ordinal() ) loopTree(); + if( _phase.ordinal() < p1 && _phase.ordinal() < Phase.Select .ordinal() && cpu != null ) instSelect(cpu,callingConv); + if( _phase.ordinal() < p1 && _phase.ordinal() < Phase.Schedule .ordinal() ) GCM(); + if( _phase.ordinal() < p1 && _phase.ordinal() < Phase.LocalSched.ordinal() ) localSched(); + if( _phase.ordinal() < p1 && _phase.ordinal() < Phase.RegAlloc .ordinal() ) regAlloc(); + if( _phase.ordinal() < p1 && _phase.ordinal() < Phase.Encoding .ordinal() ) encode(); return this; } @@ -122,39 +123,39 @@ public int iDepthFrom(int idepth) { // Compute "function indices": FIDX. // Each new request at the same signature gets a new FIDX. - private final HashMap FIDXS = new HashMap<>(); - public SONTypeFunPtr makeFun( SONTypeTuple sig, SONType ret ) { + private final HashMap FIDXS = new HashMap<>(); + public TypeFunPtr makeFun( TypeTuple sig, Type ret ) { Integer i = FIDXS.get(sig); int fidx = i==null ? 0 : i; FIDXS.put(sig,fidx+1); // Track count per sig assert fidx<64; // TODO: need a larger FIDX space - return SONTypeFunPtr.make((byte)2,sig,ret, 1L< _linker = new HashMap<>(); + private final HashMap _linker = new HashMap<>(); // Parser object public final Compiler P; @@ -229,7 +230,7 @@ public CodeGen loopTree() { _phase = Phase.LoopTree; long t0 = System.currentTimeMillis(); // Build the loop tree, fix never-exit loops - _start.buildLoopTree(_stop); + _start.buildLoopTree(_start,_stop); _tLoopTree = (int)(System.currentTimeMillis() - t0); return this; } @@ -257,7 +258,7 @@ public CodeGen loopTree() { public CodeGen instSelect( String cpu, String callingConv ) { return instSelect(cpu,callingConv,PORTS); } public CodeGen instSelect( String cpu, String callingConv, String base ) { assert _phase.ordinal() == Phase.LoopTree.ordinal(); - _phase = Phase.InstSelect; + _phase = Phase.Select; _callingConv = callingConv; @@ -288,14 +289,14 @@ public CodeGen instSelect( String cpu, String callingConv, String base ) { _rpcMask = new RegMask(_mach.rpc()); _retMasks[3] = _rpcMask; - // Convert to machine ops long t0 = System.currentTimeMillis(); _uid = 1; // All new machine nodes reset numbering var map = new IdentityHashMap(); _instSelect( _stop, map ); _stop = ( StopNode)map.get(_stop ); - _start = (StartNode)map.get(_start); + StartNode start = (StartNode)map.get(_start); + _start = start==null ? new StartNode(_start) : start; _instOuts(_stop,visit()); _visit.clear(); _tInsSel = (int)(System.currentTimeMillis() - t0); @@ -326,8 +327,6 @@ private Node _instSelect( Node n, IdentityHashMap map ) { if( x instanceof MachNode mach ) mach.postSelect(this); // Post selection action - // Updates forward edges only. - n._outputs.clear(); return x; } @@ -351,7 +350,7 @@ private void _instOuts( Node n, BitSet visit ) { // Global schedule (code motion) nodes public CodeGen GCM() { return GCM(false); } public CodeGen GCM( boolean show) { - assert _phase.ordinal() <= Phase.InstSelect.ordinal(); + assert _phase.ordinal() <= Phase.Select.ordinal(); _phase = Phase.Schedule; long t0 = System.currentTimeMillis(); @@ -451,8 +450,10 @@ public CodeGen exportELF(String fname) throws IOException { String printCFG() { if( _cfg==null ) return "no CFG"; SB sb = new SB(); - for( CFGNode cfg : _cfg ) - IRPrinter.printLine(cfg,sb); + for( CFGNode cfg : _cfg ) { + sb.fix(8,""+cfg._idepth); + IRPrinter.printLine( cfg, sb ); + } return sb.toString(); } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/ElfFile.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/ElfFile.java index 490b921..d5b3462 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/ElfFile.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/ElfFile.java @@ -9,7 +9,6 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.HashMap; -import java.util.Map; public class ElfFile { @@ -213,7 +212,7 @@ private void pushSection(Section s) { } /* creates function and stores where it starts*/ - private final HashMap _funcs = new HashMap<>(); + private final HashMap _funcs = new HashMap<>(); private void encodeFunctions(SymbolSection symbols, DataSection text) { for( int i=0; i<_code._cfg._len; i++ ) { if( !(_code._cfg.at(i) instanceof FunNode fun) ) continue; @@ -274,8 +273,6 @@ public void export(String fname) throws IOException { int start_global = num+1; // Add one to skip the final .rela.text local symbol for( Symbol a: symbols._symbols ) a._index = start_global++; - int bigConIdx = start_global; - start_global += enc._bigCons.size(); // create .text relocations DataSection text_rela = new DataSection(".rela.text", 4 /* SHT_RELA */); @@ -299,10 +296,10 @@ public void export(String fname) throws IOException { // Write relocations for the constant pool for( Encoding.Relo relo : enc._bigCons.values() ) { - Symbol glob = new Symbol("GLOB$"+bigConIdx, rdata._index, SYM_BIND_GLOBAL, SYM_TYPE_FUNC); + Symbol glob = new Symbol("CPOOL$"+start_global, rdata._index, SYM_BIND_GLOBAL, SYM_TYPE_FUNC); glob._value = relo._target; - glob._size = 1 << relo._t.log_size(); - glob._index = bigConIdx++; + glob._size = relo._t.size(); + glob._index = start_global++; symbols.push(glob); write8(text_rela._contents, relo._opStart+relo._off); write8(text_rela._contents, ((long)glob._index << 32L) | relo._elf ); @@ -314,6 +311,7 @@ public void export(String fname) throws IOException { text_rela._info = text._index; pushSection(text_rela); + // Final .rela.text symbol Symbol sym = new Symbol(text_rela._name, num++, SYM_BIND_LOCAL, SYM_TYPE_SECTION); sym._name_pos = text_rela._name_pos; sym._size = text_rela.size(); diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/Encoding.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/Encoding.java index 1fc124e..68c7f7f 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/Encoding.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/Encoding.java @@ -1,7 +1,6 @@ package com.compilerprogramming.ezlang.compiler.codegen; import com.compilerprogramming.ezlang.compiler.Ary; -import com.compilerprogramming.ezlang.compiler.SB; import com.compilerprogramming.ezlang.compiler.Utils; import com.compilerprogramming.ezlang.compiler.nodes.*; import com.compilerprogramming.ezlang.compiler.sontypes.*; @@ -47,12 +46,12 @@ public static class BAOS extends ByteArrayOutputStream { // Big Constant relocation info. public static class Relo { public final Node _op; - public final SONType _t; // Constant type + public final Type _t; // Constant type public final byte _off; // Offset from start of opcode public final byte _elf; // ELF relocation type, e.g. 2/PC32 public int _target; // Where constant is finally placede public int _opStart; // Opcode start - Relo( Node op, SONType t, byte off, byte elf ) { + Relo(Node op, Type t, byte off, byte elf ) { _op=op; _t=t; _off=off; _elf=elf; } } @@ -99,12 +98,12 @@ static void padN(int n, BAOS bits) { } // Convenience for writing log-N - static void addN( int log, SONType t, BAOS bits ) { - long x = t instanceof SONTypeInteger ti + static void addN( int log, Type t, BAOS bits ) { + long x = t instanceof TypeInteger ti ? ti.value() : log==3 - ? Double.doubleToRawLongBits( ((SONTypeFloat)t).value()) - : Float.floatToRawIntBits((float)((SONTypeFloat)t).value()); + ? Double.doubleToRawLongBits( ((TypeFloat)t).value()) + : Float.floatToRawIntBits((float)((TypeFloat)t).value()); addN(log,x,bits); } static void addN( int log, long x, BAOS bits ) { @@ -129,7 +128,7 @@ public Encoding relo( CallNode call ) { return this; } public Encoding relo( ConstantNode con ) { - SONTypeFunPtr tfp = (SONTypeFunPtr)con._con; + TypeFunPtr tfp = (TypeFunPtr)con._con; _internals.put(con,_code.link(tfp)); return this; } @@ -139,14 +138,14 @@ public void jump( CFGNode jmp, CFGNode dst ) { final HashMap _externals = new HashMap<>(); - public Encoding external( Node call, String extern ) { - _externals.put(call,extern); + public Encoding external( Node n, String extern ) { + _externals.put(n,extern); return this; } // Store t as a 32/64 bit constant in the code space; generate RIP-relative // addressing to load it - public void largeConstant( Node relo, SONType t, int off, int elf ) { + public void largeConstant( Node relo, Type t, int off, int elf ) { assert t.isConstant(); assert (byte)off == off; assert (byte)elf == elf; @@ -184,12 +183,10 @@ private void basicBlockLayout() { Ary rpo = new Ary<>(CFGNode.class); rpos.put(_code._start.loop(),rpo); BitSet visit = _code.visit(); - //IdentityHashMap looptail = new IdentityHashMap<>(); rpo.add(_code._stop); for( Node n : _code._start._outputs ) if( n instanceof FunNode fun ) { int x = rpo._len; - //_rpo_cfg2(fun, visit, rpo, looptail); _rpo_cfg(fun, visit, rpos ); assert rpo.at(x) instanceof ReturnNode; } @@ -300,7 +297,7 @@ private static boolean shouldInvert(CFGNode t, CFGNode f, int bld) { private static boolean forwardsEmptyScan( CFGNode c, int bld ) { if( c.nOuts()!=1 || c.loopDepth()!=bld ) return false; return c.uctrl() instanceof RegionNode cfg && - (cfg instanceof LoopNode || forwardsEmptyScan(cfg,bld)); + ((cfg instanceof LoopNode && cfg._ltree==c._ltree) || forwardsEmptyScan(cfg,bld)); } // Is the CFG from "next" to the end empty? This means jumping to "next" @@ -388,6 +385,23 @@ private void compactShortForm() { } + // Go again, inserting padding on function headers. Since no + // short-jumps span function headers, the padding will not make any + // short jumps fail. + for( int i=0; i 0 ) { // If no short-form ops, nothing to do here @@ -423,47 +437,90 @@ void patchLocalRelocations() { void writeConstantPool( BAOS bits, boolean patch ) { padN(16,bits); - HashMap targets = new HashMap<>(); - - // By log size - for( int log = 3; log >= 0; log-- ) { - // Write the 8-byte constants - for( Node op : _bigCons.keySet() ) { - Relo relo = _bigCons.get(op); - if( relo._t.log_size()==log ) { - // Map from relo to constant start and patch - Integer target = targets.get(relo._t); - if( target==null ) { - targets.put(relo._t,target = bits.size()); - // Put constant into code space. - if( relo._t instanceof SONTypeTuple tt ) // Constant tuples put all entries - for( SONType tx : tt._types ) - addN(log,tx,bits); - else - addN(log,relo._t,bits); + // radix sort the big constants by alignment + Ary[] raligns = new Ary[5]; + for( Node op : _bigCons.keySet() ) { + Relo relo = _bigCons.get(op); + int align = relo._t.alignment(); + Ary relos = raligns[align]==null ? (raligns[align]=new Ary<>(Relo.class)) : raligns[align]; + relos.add(relo); + } + + + // Types can be used more than once; collapse the dups + HashMap targets = new HashMap<>(); + + // By alignment + for( int align = 4; align >= 0; align-- ) { + Ary relos = raligns[align]; + if( relos == null ) continue; + for( Relo relo : relos ) { + // Map from relo to constant start and patch + Integer target = targets.get(relo._t); + if( target==null ) { + targets.put(relo._t,target = bits.size()); + // Write constant into constant pool + switch( relo._t ) { + case TypeTuple tt -> cpool(align,bits,tt); + case TypeStruct ts -> cpool(bits,ts); + // Simple primitive (e.g. larger int, float) + default -> addN(align,relo._t,bits); } - relo._target = target; - relo._opStart= _opStart[op._nid]; - // Go ahead and locally patch in-memory - if( patch ) - ((RIPRelSize)op).patch(this, relo._opStart, _opLen[op._nid], relo._target - relo._opStart); } + // Record target address and opcode start + relo._target = target; + relo._opStart= _opStart[relo._op._nid]; + // Go ahead and locally patch in-memory + if( patch ) + ((RIPRelSize)relo._op).patch(this, relo._opStart, _opLen[relo._op._nid], relo._target - relo._opStart); } } } + // Constant tuples put all entries at same alignment + private void cpool(int align, BAOS bits, TypeTuple tt) { + for( Type tx : tt._types ) + addN(align,tx,bits); + } + + // Structs use internal field layout + private void cpool( BAOS bits, TypeStruct ts ) { + // Field order by offset + int[] layout = ts.layout(); + int off=0; // offset in the struct + for( int fn=0; fn SENTINAL_CALLOC; + case "calloc" -> SENTINEL_CALLOC; + case "write" -> SENTINEL_WRITE ; default -> throw Utils.TODO(); }; ((RIPRelSize)src).patch(this, start, _opLen[src._nid], target - start); diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/GlobalCodeMotion.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/GlobalCodeMotion.java index 627e7e0..f6f2f2c 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/GlobalCodeMotion.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/GlobalCodeMotion.java @@ -32,7 +32,6 @@ public static void buildCFG( CodeGen code ) { // Post-Order of CFG private static void _rpo_cfg(CFGNode def, Node use, BitSet visit, Ary rpo) { - if( use instanceof CallNode call ) call.unlink_all(); if( !(use instanceof CFGNode cfg) || visit.get(cfg._nid) ) return; // Been there, done that if( def instanceof ReturnNode && use instanceof CallEndNode ) @@ -166,11 +165,11 @@ private static void breadth(Node stop, Node[] ns, CFGNode[] late) { // New makes new memory, never crushes load memory !(memuse instanceof NewNode) && // Load-use directly defines memory - (memuse._type instanceof SONTypeMem || + (memuse._type instanceof TypeMem || // Load-use directly defines memory memuse instanceof CallNode || // Load-use indirectly defines memory - (memuse._type instanceof SONTypeTuple tt && tt._types[ld._alias] instanceof SONTypeMem)) ) + (memuse._type instanceof TypeTuple tt && tt._types[ld._alias] instanceof TypeMem)) ) continue outer; // All uses done, schedule @@ -178,14 +177,22 @@ private static void breadth(Node stop, Node[] ns, CFGNode[] late) { } // Walk all inputs and put on worklist, as their last-use might now be done - for( Node def : n._inputs ) - if( def!=null && late[def._nid]==null ) { + for( Node def : n._inputs ) { + if( def!=null && late[def._nid]==null ) work.push(def); - // if the def has a load use, maybe the load can fire + // if the def has a load use, maybe the load can fire + if( def!=null ) for( Node out : def._outputs ) if( out instanceof MemOpNode ld && ld._isLoad && late[ld._nid]==null ) work.push(ld); + } + + if( n instanceof LoopNode loop ) { + for( Node phi : loop._outputs ) { + if( phi instanceof PhiNode && late[phi._nid]==null ) + work.push(phi); } + } } } @@ -274,7 +281,7 @@ private static CFGNode find_anti_dep(CFGNode lca, MemOpNode load, CFGNode early, for( Node mem : load.mem()._outputs ) { switch( mem ) { case MemOpNode st: - if( !st._isLoad ) { + if( !st._isLoad && load._alias == st._alias ) { assert late[mem._nid] != null; lca = anti_dep( load, late[mem._nid], mem.cfg0(), lca, st ); } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/Machine.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/Machine.java index 4115e57..3a9d9e9 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/Machine.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/Machine.java @@ -1,7 +1,7 @@ package com.compilerprogramming.ezlang.compiler.codegen; import com.compilerprogramming.ezlang.compiler.nodes.*; -import com.compilerprogramming.ezlang.compiler.sontypes.SONTypeFunPtr; +import com.compilerprogramming.ezlang.compiler.sontypes.TypeFunPtr; abstract public class Machine { // Human readable machine name. Something like "x86-64" or "arm" or "risc5" @@ -21,9 +21,9 @@ abstract public class Machine { // for the function itself, or for *outgoing* calls, the maximum stack slot // given to the incoming function arguments (stack slots reserved for // incoming arguments). - public abstract RegMask callArgMask(SONTypeFunPtr tfp, int arg, int maxArgSlot); + public abstract RegMask callArgMask(TypeFunPtr tfp, int arg, int maxArgSlot); // Return register mask, based on signature (GPR vs FPR) - public abstract RegMask retMask(SONTypeFunPtr tfp); + public abstract RegMask retMask(TypeFunPtr tfp); // Return PC register public abstract int rpc(); // Return a MachNode unconditional branch @@ -92,6 +92,6 @@ abstract public class Machine { // Maximum stack slot (or 0) for the args in this TFP. This will include // shadow slots if defined in the ABI, even if all arguments are passed in // registers. - public abstract short maxArgSlot(SONTypeFunPtr tfp); + public abstract short maxArgSlot(TypeFunPtr tfp); } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/RegAlloc.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/RegAlloc.java index 0c778d5..c75d6c4 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/RegAlloc.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/RegAlloc.java @@ -162,7 +162,7 @@ public void regAlloc() { } // Cache reg masks for New and Call for( CFGNode bb : _code._cfg ) { - if( bb instanceof CallEndNode cend ) cend.cacheRegs(_code); + if( bb instanceof CallEndMach cend ) cend.cacheRegs(_code); for( Node n : bb._outputs ) if( n instanceof NewNode nnn ) nnn.cacheRegs(_code); } @@ -287,24 +287,25 @@ boolean splitEmptyMaskByUse( byte round, LRG lrg ) { // all registers anyways. if( rclass._len <= 1 || ncalls > 1 ) return false; - // Split by classh + // Split by class Ary ns = new Ary<>(Node.class); for( RegMask rmask : rclass ) { ns.addAll(def._outputs); - Node split = makeSplit(def,"popular",round,lrg); + Node split = makeSplit(def,"popular",round,lrg,rmask); split.insertAfter( def ); if( split.nIns()>1 ) split.setDef(1,def); // all uses by class to split - for( Node use : ns ) { + for( int j=0; j < def._outputs._len; j++ ) { + Node use = def._outputs.at(j); if( use instanceof MachNode mach && use!=split ) { // Check all use inputs for n, in case there's several for( int i = 1; i < use.nIns(); i++ ) // Find a def input, and check register class - if( use.in( i ) == def ) { + if( use.in( i ) == def && mach.regmap( i ).overlap( rmask ) ) { RegMask m = mach.regmap( i ); if( m!=null && mach.regmap( i ).overlap( rmask ) ) // Modify use to use the split version specialized to this rclass - use.setDefOrdered( i, split ); + { use.setDefOrdered( i, split ); j--; break; } } } } @@ -500,15 +501,17 @@ void insertBefore(Node n, int i, String kind, byte round, LRG lrg, boolean skip) Node def = n.in(i); // Effective block for use CFGNode cfg = n instanceof PhiNode phi ? phi.region().cfg(i) : n.cfg0(); + // Use-side RegMask, if available + RegMask umask = n instanceof MachNode mach ? mach.regmap(i) : null; // Def is a split ? if( skip && def instanceof SplitNode ) { - boolean singleReg = n instanceof MachNode mach && mach.regmap(i).size1(); + boolean singleReg = umask!=null && umask.size1(); // Same block, multiple registers, split is only used by n, // assume this is good enough and do not split again. if( cfg==def.cfg0() && def.nOuts()==1 && !singleReg ) return; } - makeSplit(def,kind,round,lrg).insertBefore(n, i); + makeSplit(def,kind,round,lrg,umask).insertBefore(n, i); // Skip split-of-split same block if( skip && def instanceof SplitNode && cfg==def.cfg0() ) n.in(i).setDefOrdered(1,def.in(1)); @@ -535,8 +538,9 @@ public void insertAfterAndReplace( Node split, Node def, boolean must ) { } } - private Node makeSplit( Node def, String kind, byte round, LRG lrg ) { - Node split = def instanceof MachNode mach && mach.isClone() + private Node makeSplit( Node def, String kind, byte round, LRG lrg, RegMask umask ) { + // Clone simple constants if possible + Node split = def instanceof MachNode mach && mach.isClone() && (umask==null || mach.outregmap().overlap(umask)) ? mach.copy() : _code._mach.split(kind,round,lrg); _lrgs.put(split,lrg); @@ -554,13 +558,13 @@ private SplitNode makeSplit( String kind, byte round, LRG lrg ) { private void postColor() { int maxReg = -1; for( CFGNode bb : _code._cfg ) { // For all ops - if( bb instanceof FunNode fun ) + if( bb instanceof FunNode ) maxReg = -1; // Reset for new function // Compute frame size, based on arguments and largest reg seen if( bb instanceof ReturnNode ret ) ret.fun().computeFrameAdjust(_code,maxReg); // Raise frame size by max stack args passed, even if ignored - if( bb instanceof CallEndNode cend ) + if( bb instanceof CallEndMach cend ) maxReg = Math.max(maxReg,cend._xslot); for( int j=0; j 2 ) { @@ -175,8 +153,8 @@ static boolean spine_cmp( Node hi, Node lo, Node dep ) { if( lo._type.isConstant() ) return false; if( hi._type.isConstant() ) return true ; - if( lo instanceof PhiNode lphi && lphi.region()._type== SONType.XCONTROL ) return false; - if( hi instanceof PhiNode hphi && hphi.region()._type== SONType.XCONTROL ) return false; + if( lo instanceof PhiNode lphi && lphi.region()._type==Type.XCONTROL ) return false; + if( hi instanceof PhiNode hphi && hphi.region()._type==Type.XCONTROL ) return false; if( lo instanceof PhiNode && lo.allCons(dep) ) return false; if( hi instanceof PhiNode && hi.allCons(dep) ) return true ; @@ -190,11 +168,4 @@ static boolean spine_cmp( Node hi, Node lo, Node dep ) { @Override Node copy(Node lhs, Node rhs) { return new AddNode(lhs,rhs); } @Override Node copyF() { return new AddFNode(null,null); } -// FIXME Dibyendu -// @Override public Parser.ParseException err() { -// if( in(1)._type.isHigh() || in(2)._type.isHigh() ) return null; -// if( !(in(1)._type instanceof SONTypeInteger) ) return Parser.error("Cannot '"+label()+"' " + in(1)._type,null); -// if( !(in(2)._type instanceof SONTypeInteger) ) return Parser.error("Cannot '"+label()+"' " + in(2)._type,null); -// return null; -// } } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/AndNode.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/AndNode.java index f36997f..9308283 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/AndNode.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/AndNode.java @@ -1,39 +1,29 @@ package com.compilerprogramming.ezlang.compiler.nodes; -import com.compilerprogramming.ezlang.compiler.sontypes.SONType; -import com.compilerprogramming.ezlang.compiler.sontypes.SONTypeInteger; +import com.compilerprogramming.ezlang.compiler.sontypes.Type; +import com.compilerprogramming.ezlang.compiler.sontypes.TypeInteger; -public class AndNode extends LogicalNode { +public class AndNode extends ArithNode { public AndNode(Node lhs, Node rhs) { super(lhs, rhs); } @Override public String label() { return "And"; } @Override public String op() { return "&"; } - @Override public String glabel() { return "&"; } - @Override - public SONType compute() { - SONType t1 = in(1)._type, t2 = in(2)._type; - if( t1.isHigh() || t2.isHigh() ) - return SONTypeInteger.TOP; - if( t1 instanceof SONTypeInteger i0 && - t2 instanceof SONTypeInteger i1 ) { - if( i0.isConstant() && i1.isConstant() ) - return SONTypeInteger.constant(i0.value()&i1.value()); - // Sharpen allowed bits if either value is narrowed - long mask = i0.mask() & i1.mask(); - return mask < 0 ? SONTypeInteger.BOT : SONTypeInteger.make(0,mask); - } - return SONTypeInteger.BOT; + @Override long doOp( long x, long y ) { return x & y; } + @Override TypeInteger doOp(TypeInteger x, TypeInteger y) { + // Sharpen allowed bits if either value is narrowed + long mask = x.mask() & y.mask(); + return mask < 0 ? TypeInteger.BOT : TypeInteger.make(0,mask); } @Override public Node idealize() { Node lhs = in(1); Node rhs = in(2); - SONType t1 = lhs._type; - SONType t2 = rhs._type; - if( !(t1 instanceof SONTypeInteger && t2 instanceof SONTypeInteger t2i) ) + Type t1 = lhs._type; + Type t2 = rhs._type; + if( !(t1 instanceof TypeInteger && t2 instanceof TypeInteger t2i) ) return null; // Malformed, e.g. (17 & 3.14) // And of -1. We do not check for (-1&x) because this will already @@ -50,9 +40,10 @@ public Node idealize() { // Do we have ((x & (phi cons)) & (phi cons)) ? // Push constant up through the phi: x & (phi con0&con0 con1&con1...) Node phicon = AddNode.phiCon(this,true); - if( phicon!=null ) return phicon; + if( phicon!=null ) + return phicon; - return null; + return super.idealize(); } @Override Node copy(Node lhs, Node rhs) { return new AndNode(lhs,rhs); } } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/ArithNode.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/ArithNode.java new file mode 100644 index 0000000..acac980 --- /dev/null +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/ArithNode.java @@ -0,0 +1,98 @@ +package com.compilerprogramming.ezlang.compiler.nodes; + +import com.compilerprogramming.ezlang.compiler.Compiler; +import com.compilerprogramming.ezlang.compiler.sontypes.Type; +import com.compilerprogramming.ezlang.compiler.sontypes.TypeInteger; +import com.compilerprogramming.ezlang.exceptions.CompilerException; + +import java.util.BitSet; + +public abstract class ArithNode extends Node { + // Source location for late reported errors + + public ArithNode(Node lhs, Node rhs) { super(null, lhs, rhs); } + @Override public String glabel() { return op(); } + abstract String op(); + + @Override + public StringBuilder _print1(StringBuilder sb, BitSet visited) { + in(1)._print0(sb.append("("), visited); + in(2)._print0(sb.append(op()), visited); + return sb.append(")"); + } + + abstract long doOp(long x, long y); + abstract TypeInteger doOp(TypeInteger x, TypeInteger y); + + // Generic airthmetic op math: high returns high; low returns low; 2 + // constants fold; only 2 non-constants call specialized math. + @Override + public final TypeInteger compute() { + Type t1 = in(1)._type, t2 = in(2)._type; + if( t1.isHigh() || t2.isHigh() ) + return TypeInteger.TOP; + if( t1 instanceof TypeInteger x && + t2 instanceof TypeInteger y ) + return x.isConstant() && y.isConstant() + ? con(x,y) + : doOp(x,y); + return TypeInteger.BOT; + } + + private TypeInteger con( Type t1, Type t2 ) { + return TypeInteger.constant( doOp( ((TypeInteger)t1).value(), ((TypeInteger)t2).value()) ); + } + + // Check for "op(Phi(con,x),Phi(con,y))" and push-up through the Phi. + // Note that this is the exact reverse of Phi pulling a common op down + // to reduce total op-count. We don't get in an endless push-up + // push-down peephole cycle because the constants all fold first. + // Returns "Phi(op(con,con),op(x,y))". + + // This check is slightly different from the + + // Expected to be called after other ideal checks are done. + @Override public Node idealize() { + if( in(1) instanceof PhiNode lhs && + in(2) instanceof PhiNode rhs && + lhs.nIns() >= 2 && !lhs.inProgress() && + lhs.region()==rhs.region() ) { + // Profit check: only 1 instance of `this` will remain, all the + // others will fold to constants. + int cnt=0; + for( int i=1; i in(2)._nid ) // Equals sorts by NID otherwise: non.high == non.low becomes non.low == non.high - return in(1)._type instanceof SONTypeFloat ? new EQF(in(2),in(1)) : new EQ(in(2),in(1)); + return in(1)._type instanceof TypeFloat ? new EQF(in(2),in(1)) : new EQ(in(2),in(1)); } // Equals X==0 becomes a !X - if( (in(2)._type == ZERO || in(2)._type == SONType.NIL) ) + if( (in(2)._type == ZERO || in(2)._type == Type.NIL) ) return new NotNode(in(1)); } @@ -83,7 +83,7 @@ public Node idealize() { public static class EQ extends BoolNode { public EQ(Node lhs, Node rhs) { super(lhs,rhs); } public String op() { return "=="; } - SONTypeInteger doOp(SONTypeInteger i1, SONTypeInteger i2) { + TypeInteger doOp(TypeInteger i1, TypeInteger i2) { if( i1==i2 && i1.isConstant() ) return TRUE; if( i1._max < i2._min || i1._min > i2._max ) return FALSE; return BOOL; @@ -95,7 +95,7 @@ SONTypeInteger doOp(SONTypeInteger i1, SONTypeInteger i2) { public static class NE extends BoolNode { public NE(Node lhs, Node rhs) { super(lhs,rhs); } public String op() { return "!="; } - SONTypeInteger doOp(SONTypeInteger i1, SONTypeInteger i2) { + TypeInteger doOp(TypeInteger i1, TypeInteger i2) { if( i1==i2 && i1.isConstant() ) return TRUE; if( i1._max < i2._min || i1._min > i2._max ) return FALSE; return BOOL; @@ -108,7 +108,7 @@ public static class LT extends BoolNode { public LT(Node lhs, Node rhs) { super(lhs,rhs); } public String op() { return "<" ; } public String glabel() { return "<"; } - SONTypeInteger doOp(SONTypeInteger i1, SONTypeInteger i2) { + TypeInteger doOp(TypeInteger i1, TypeInteger i2) { if( i1._max < i2._min ) return TRUE; if( i1._min >= i2._max ) return FALSE; return BOOL; @@ -116,11 +116,12 @@ SONTypeInteger doOp(SONTypeInteger i1, SONTypeInteger i2) { Node copy(Node lhs, Node rhs) { return new LT(lhs,rhs); } Node copyF() { return new LTF(null,null); } } + public static class LE extends BoolNode { public LE(Node lhs, Node rhs) { super(lhs,rhs); } public String op() { return "<="; } public String glabel() { return "<="; } - SONTypeInteger doOp(SONTypeInteger i1, SONTypeInteger i2) { + TypeInteger doOp(TypeInteger i1, TypeInteger i2) { if( i1._max <= i2._min ) return TRUE; if( i1._min > i2._max ) return FALSE; return BOOL; @@ -129,16 +130,31 @@ SONTypeInteger doOp(SONTypeInteger i1, SONTypeInteger i2) { Node copyF() { return new LEF(null,null); } } - public static class EQF extends EQ { public EQF(Node lhs, Node rhs) { super(lhs,rhs); } boolean doOp(double lhs, double rhs) { return lhs == rhs; } public boolean isFloat() { return true; } } - public static class LTF extends LT { public LTF(Node lhs, Node rhs) { super(lhs,rhs); } boolean doOp(double lhs, double rhs) { return lhs < rhs; } public boolean isFloat() { return true; } } - public static class LEF extends LE { public LEF(Node lhs, Node rhs) { super(lhs,rhs); } boolean doOp(double lhs, double rhs) { return lhs <= rhs; } public boolean isFloat() { return true; } } + public static class EQF extends EQ { + public EQF(Node lhs, Node rhs) { super(lhs,rhs); } + @Override boolean doOp(double lhs, double rhs) { return lhs == rhs; } + @Override public boolean isFloat() { return true; } + @Override Node copy(Node lhs, Node rhs) { return new EQF(lhs,rhs); } + } + public static class LTF extends LT { + public LTF(Node lhs, Node rhs) { super(lhs,rhs); } + @Override boolean doOp(double lhs, double rhs) { return lhs < rhs; } + @Override public boolean isFloat() { return true; } + @Override Node copy(Node lhs, Node rhs) { return new LTF(lhs,rhs); } + } + public static class LEF extends LE { + public LEF(Node lhs, Node rhs) { super(lhs,rhs); } + @Override boolean doOp(double lhs, double rhs) { return lhs <= rhs; } + @Override public boolean isFloat() { return true; } + @Override Node copy(Node lhs, Node rhs) { return new LEF(lhs,rhs); } + } // Unsigned less that, for range checks. Not directly user writable. public static class ULT extends BoolNode { public ULT(Node lhs, Node rhs) { super(lhs,rhs); } public String op() { return "u<" ; } public String glabel() { return "u<"; } - SONTypeInteger doOp(SONTypeInteger i1, SONTypeInteger i2) { + TypeInteger doOp(TypeInteger i1, TypeInteger i2) { if( Long.compareUnsigned(i1._max,i2._min) < 0 ) return TRUE; if( Long.compareUnsigned(i1._min,i2._max) >= 0 ) return FALSE; return BOOL; diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/CFGNode.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/CFGNode.java index cda5c80..23b4c82 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/CFGNode.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/CFGNode.java @@ -122,7 +122,19 @@ int depth() { // Tag all CFG Nodes with their containing LoopNode; LoopNodes themselves // also refer to *their* containing LoopNode, as well as have their depth. // Start is a LoopNode which contains all at depth 1. - public void buildLoopTree(StopNode stop) { + public void buildLoopTree(StartNode start, StopNode stop) { + // Unlink all linked calls. This can remove RPC constants which + // shuffled the StartNode outputs so requires a while loop. + boolean done=false; + while(!done) { + done = true; + for( Node use : start._outputs ) + if( use instanceof FunNode fun ) + for( Node c : fun._inputs ) + if( c instanceof CallNode call ) + { call.unlink_all(); done=false; } + } + _ltree = stop._ltree = Compiler.XCTRL._ltree = new LoopTree((StartNode)this); _bltWalk(2,null,stop, new BitSet()); } @@ -140,8 +152,8 @@ int _bltWalk( int pre, FunNode fun, StopNode stop, BitSet post ) { for( Node use : _outputs ) { if( !(use instanceof CFGNode usecfg) ) continue; if( skip(usecfg) ) continue; - if( usecfg._type == SONType.XCONTROL || // Do not walk dead control - usecfg._type == SONTypeTuple.IF_NEITHER ) // Nor dead IFs + if( usecfg._type == Type.XCONTROL || // Do not walk dead control + usecfg._type == TypeTuple.IF_NEITHER ) // Nor dead IFs continue; // Child visited but not post-visited? if( !post.get(usecfg._nid) ) { diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/CProjNode.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/CProjNode.java index 9c18492..1aec013 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/CProjNode.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/CProjNode.java @@ -1,8 +1,8 @@ package com.compilerprogramming.ezlang.compiler.nodes; import com.compilerprogramming.ezlang.compiler.Compiler; -import com.compilerprogramming.ezlang.compiler.sontypes.SONType; -import com.compilerprogramming.ezlang.compiler.sontypes.SONTypeTuple; +import com.compilerprogramming.ezlang.compiler.sontypes.Type; +import com.compilerprogramming.ezlang.compiler.sontypes.TypeTuple; import java.util.BitSet; public class CProjNode extends CFGNode { @@ -29,17 +29,17 @@ public CProjNode(Node ctrl, int idx, String label) { public CFGNode ctrl() { return cfg(0); } @Override - public SONType compute() { - SONType t = ctrl()._type; - return t instanceof SONTypeTuple tt ? tt._types[_idx] : SONType.BOTTOM; + public Type compute() { + Type t = ctrl()._type; + return t instanceof TypeTuple tt ? tt._types[_idx] : Type.BOTTOM; } @Override public Node idealize() { - if( ctrl()._type instanceof SONTypeTuple tt ) { - if( tt._types[_idx]== SONType.XCONTROL ) + if( ctrl()._type instanceof TypeTuple tt ) { + if( tt._types[_idx]== Type.XCONTROL ) return Compiler.XCTRL; // We are dead - if( ctrl() instanceof IfNode && tt._types[1-_idx]== SONType.XCONTROL ) // Only true for IfNodes + if( ctrl() instanceof IfNode && tt._types[1-_idx]== Type.XCONTROL ) // Only true for IfNodes return ctrl().in(0); // We become our input control } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/CallEndMach.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/CallEndMach.java new file mode 100644 index 0000000..9474a43 --- /dev/null +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/CallEndMach.java @@ -0,0 +1,36 @@ +package com.compilerprogramming.ezlang.compiler.nodes; + +import com.compilerprogramming.ezlang.compiler.SB; +import com.compilerprogramming.ezlang.compiler.codegen.*; + +public class CallEndMach extends CallEndNode implements MachNode { + public CallEndMach( CallEndNode n ) { super(n); } + // MachNode specifics, shared across all CPUs + public int _xslot; + private RegMask _retMask; + private RegMask _kills; + public void cacheRegs(CodeGen code) { + // Return mask depends on TFP (either GPR or FPR) + _retMask = code._mach.retMask(call().tfp()); + // Kill mask is all caller-saves, and any mirror stack slots for args + // in registers. + RegMaskRW kills = code._callerSave.copy(); + // Start of stack slots + int maxReg = code._mach.regs().length; + // Incoming function arg slots, all low numbered in the RA + int fslot = fun()._maxArgSlot; + // Killed slots for this calls outgoing args + int xslot = code._mach.maxArgSlot(call().tfp()); + _xslot = (maxReg+fslot)+xslot; + for( int i=0; i1 ) { assert nIns()==2; // Linked exactly once for a constant - ret = ((SONTypeTuple)in(1)._type).ret(); // Return type + ret = ((TypeTuple)in(1)._type).ret(); // Return type } } - return SONTypeTuple.make(call._type, SONTypeMem.BOT,ret); + return TypeTuple.make(call._type,TypeMem.BOT,ret); } @Override @@ -59,12 +65,14 @@ public Node idealize() { // Trivial inlining: call site calls a single function; single function // is only called by this call site. - if( false && !_folding && nIns()==2 && in(0) instanceof CallNode call ) { + // EZ Lang - we do not support inlining calls yet + // EZ Lang - possibly requires updating the type dict to say inlined function is dead + if( ALLOW_INLINING_CALLS && !_folding && nIns()==2 && in(0) instanceof CallNode call ) { Node fptr = call.fptr(); if( fptr.nOuts() == 1 && // Only user is this call fptr instanceof ConstantNode && // We have an immediate call // Function is being called, and its not-null - fptr._type instanceof SONTypeFunPtr tfp && tfp.notNull() && + fptr._type instanceof TypeFunPtr tfp && tfp.notNull() && // Arguments are correct call.err()==null ) { ReturnNode ret = (ReturnNode)in(1); @@ -106,33 +114,4 @@ public Node idealize() { return _folding ? in(1).in(idx) : null; } - // ------------ - // MachNode specifics, shared across all CPUs - public int _xslot; - private RegMask _retMask; - private RegMask _kills; - public void cacheRegs(CodeGen code) { - // Return mask depends on TFP (either GPR or FPR) - _retMask = code._mach.retMask(call().tfp()); - // Kill mask is all caller-saves, and any mirror stack slots for args - // in registers. - RegMaskRW kills = code._callerSave.copy(); - // Start of stack slots - int maxReg = code._mach.regs().length; - // Incoming function arg slots, all low numbered in the RA - int fslot = fun()._maxArgSlot; - // Killed slots for this calls outgoing args - int xslot = code._mach.maxArgSlot(call().tfp()); - _xslot = (maxReg+fslot)+xslot; - for( int i=0; i 0 ) { // Wipe out the return which matching in the linker table // Walk the (63 max) bits and link - for( ; fidxs!=0; fidxs = SONTypeFunPtr.nextFIDX(fidxs) ) { + for( ; fidxs!=0; fidxs = TypeFunPtr.nextFIDX(fidxs) ) { int fidx = Long.numberOfTrailingZeros(fidxs); - SONTypeFunPtr tfp0 = tfp.makeFrom(fidx); + TypeFunPtr tfp0 = tfp.makeFrom(fidx); FunNode fun = CodeGen.CODE.link(tfp0); if( fun!=null && !fun._folding && !linked(fun) ) progress = link(fun); @@ -149,7 +151,7 @@ public void unlink_all() { @Override public CompilerException err() { - if( !(fptr()._type instanceof SONTypeFunPtr tfp) ) + if( !(fptr()._type instanceof TypeFunPtr tfp) ) throw Utils.TODO(); if( !tfp.notNull() ) return Compiler.error( "Might be null calling "+tfp); @@ -161,6 +163,9 @@ public CompilerException err() { if( !arg(i+2)._type.isa(tfp.arg(i)) ) return Compiler.error( "Argument #"+i+" isa "+arg(i+2)._type+", but must be a "+tfp.arg(i)); + if( tfp.fidxs() < 0 ) + throw Utils.TODO(); // Infinite unknown TFPs? Should be fairly precise CG + return null; } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/CalleeSaveNode.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/CalleeSaveNode.java index a003903..bf6461b 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/CalleeSaveNode.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/CalleeSaveNode.java @@ -1,11 +1,8 @@ package com.compilerprogramming.ezlang.compiler.nodes; -import com.compilerprogramming.ezlang.compiler.Utils; import com.compilerprogramming.ezlang.compiler.codegen.Encoding; import com.compilerprogramming.ezlang.compiler.codegen.RegMask; -import com.compilerprogramming.ezlang.compiler.sontypes.SONType; -import java.util.BitSet; -import java.io.ByteArrayOutputStream; +import com.compilerprogramming.ezlang.compiler.sontypes.Type; public class CalleeSaveNode extends ProjNode implements MachNode { final RegMask _mask; @@ -21,6 +18,6 @@ public CalleeSaveNode(FunNode fun, int reg, String label) { @Override public RegMask outregmap() { return _mask; } @Override public void encoding( Encoding enc ) { } - @Override public SONType compute() { return SONType.BOTTOM; } + @Override public Type compute() { return Type.BOTTOM; } @Override public Node idealize() { return null; } } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/CastARM.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/CastMach.java similarity index 58% rename from seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/CastARM.java rename to seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/CastMach.java index 432a5b8..3fcf37b 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/CastARM.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/CastMach.java @@ -1,18 +1,19 @@ -package com.compilerprogramming.ezlang.compiler.nodes.cpus.arm; +package com.compilerprogramming.ezlang.compiler.nodes; import com.compilerprogramming.ezlang.compiler.SB; import com.compilerprogramming.ezlang.compiler.codegen.CodeGen; import com.compilerprogramming.ezlang.compiler.codegen.Encoding; import com.compilerprogramming.ezlang.compiler.codegen.RegMask; -import com.compilerprogramming.ezlang.compiler.nodes.CastNode; -import com.compilerprogramming.ezlang.compiler.nodes.MachNode; -public class CastARM extends CastNode implements MachNode { - public CastARM( CastNode cast ) { super(cast); } +/** + * Cast a pointer to read-only + */ +public class CastMach extends CastNode implements MachNode { + public CastMach( CastNode n ) { super(n); } @Override public String op() { return label(); } @Override public RegMask regmap(int i) { assert i==1; return RegMask.FULL; } @Override public RegMask outregmap() { return RegMask.FULL; } @Override public int twoAddress( ) { return 1; } @Override public void encoding( Encoding enc ) { } - @Override public void asm(CodeGen code, SB sb) { _t.print(sb.p(code.reg(in(1))).p(" isa ")); } + @Override public void asm(CodeGen code, SB sb) { sb.p(code.reg(in(1))); } } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/CastNode.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/CastNode.java index 58de87f..c37e22c 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/CastNode.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/CastNode.java @@ -1,7 +1,9 @@ package com.compilerprogramming.ezlang.compiler.nodes; import com.compilerprogramming.ezlang.compiler.Utils; -import com.compilerprogramming.ezlang.compiler.sontypes.SONType; +import com.compilerprogramming.ezlang.compiler.sontypes.Type; +import com.compilerprogramming.ezlang.compiler.sontypes.TypeInteger; +import com.compilerprogramming.ezlang.compiler.sontypes.TypeMemPtr; import com.compilerprogramming.ezlang.exceptions.CompilerException; import java.util.BitSet; @@ -9,8 +11,8 @@ // Upcast (join) the input to a t. Used after guard test to lift an input. // Can also be used to make a type-assertion if ctrl is null. public class CastNode extends Node { - public SONType _t; - public CastNode(SONType t, Node ctrl, Node in) { + public Type _t; + public CastNode(Type t, Node ctrl, Node in) { super(ctrl, in); _t = t; setType(compute()); @@ -36,7 +38,10 @@ public StringBuilder _print1(StringBuilder sb, BitSet visited) { } @Override - public SONType compute() { + public Type compute() { + // Cast array to int + if( _t == TypeInteger.BOT && in(1)._type instanceof TypeMemPtr tmp && tmp._obj.isAry() ) + return _t; return in(1)._type.join(_t); } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/ConstantNode.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/ConstantNode.java index 4eb1798..a689a00 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/ConstantNode.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/ConstantNode.java @@ -2,8 +2,8 @@ import com.compilerprogramming.ezlang.compiler.codegen.CodeGen; import com.compilerprogramming.ezlang.compiler.SB; -import com.compilerprogramming.ezlang.compiler.sontypes.SONType; -import com.compilerprogramming.ezlang.compiler.sontypes.SONTypeFunPtr; +import com.compilerprogramming.ezlang.compiler.sontypes.Type; +import com.compilerprogramming.ezlang.compiler.sontypes.TypeFunPtr; import java.util.BitSet; /** @@ -20,17 +20,17 @@ */ public class ConstantNode extends Node { - public final SONType _con; - public ConstantNode( SONType type ) { + public final Type _con; + public ConstantNode( Type type ) { super(new Node[]{CodeGen.CODE._start}); _con = _type = type; } - public ConstantNode( Node con, SONType t ) { super(con); _con = t; } + public ConstantNode( Node con, Type t ) { super(con); _con = t; } public ConstantNode( ConstantNode con ) { this(con,con._type); } - public static Node make( SONType type ) { - if( type== SONType. CONTROL ) return new CtrlNode(); - if( type== SONType.XCONTROL ) return new XCtrlNode(); + public static Node make( Type type ) { + if( type==Type. CONTROL ) return new CtrlNode(); + if( type==Type.XCONTROL ) return new XCtrlNode(); return new ConstantNode(type); } @@ -42,7 +42,7 @@ public static Node make( SONType type ) { @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) { - if( _con instanceof SONTypeFunPtr tfp && tfp.isConstant() ) { + if( _con instanceof TypeFunPtr tfp && tfp.isConstant() ) { FunNode fun = CodeGen.CODE.link(tfp); if( fun!=null && fun._name != null ) return sb.append("{ ").append(fun._name).append("}"); @@ -53,7 +53,7 @@ public StringBuilder _print1(StringBuilder sb, BitSet visited) { @Override public boolean isConst() { return true; } @Override - public SONType compute() { return _con; } + public Type compute() { return _con; } @Override public Node idealize() { return null; } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/CtrlNode.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/CtrlNode.java index 6450cdd..6131eef 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/CtrlNode.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/CtrlNode.java @@ -1,7 +1,7 @@ package com.compilerprogramming.ezlang.compiler.nodes; import com.compilerprogramming.ezlang.compiler.codegen.CodeGen; -import com.compilerprogramming.ezlang.compiler.sontypes.SONType; +import com.compilerprogramming.ezlang.compiler.sontypes.Type; import java.util.BitSet; public class CtrlNode extends CFGNode { @@ -9,6 +9,6 @@ public class CtrlNode extends CFGNode { @Override public String label() { return "Ctrl"; } @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append("Cctrl"); } @Override public boolean isConst() { return true; } - @Override public SONType compute() { return SONType.CONTROL; } + @Override public Type compute() { return Type.CONTROL; } @Override public Node idealize() { return null; } } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/DivFNode.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/DivFNode.java index 0813fa8..bbfcccf 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/DivFNode.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/DivFNode.java @@ -1,7 +1,7 @@ package com.compilerprogramming.ezlang.compiler.nodes; -import com.compilerprogramming.ezlang.compiler.sontypes.SONType; -import com.compilerprogramming.ezlang.compiler.sontypes.SONTypeFloat; +import com.compilerprogramming.ezlang.compiler.sontypes.Type; +import com.compilerprogramming.ezlang.compiler.sontypes.TypeFloat; import java.util.BitSet; @@ -20,11 +20,11 @@ public StringBuilder _print1(StringBuilder sb, BitSet visited) { } @Override - public SONType compute() { - if (in(1)._type instanceof SONTypeFloat i0 && - in(2)._type instanceof SONTypeFloat i1) { + public Type compute() { + if (in(1)._type instanceof TypeFloat i0 && + in(2)._type instanceof TypeFloat i1) { if (i0.isConstant() && i1.isConstant()) - return SONTypeFloat.constant(i0.value()/i1.value()); + return TypeFloat.constant(i0.value()/i1.value()); } return in(1)._type.meet(in(2)._type); } @@ -32,8 +32,8 @@ public SONType compute() { @Override public Node idealize() { // Div of constant - if( in(2)._type instanceof SONTypeFloat f && f.isConstant() ) - return new MulFNode(in(1),new ConstantNode(SONTypeFloat.constant(1.0/f.value())).peephole()); + if( in(2)._type instanceof TypeFloat f && f.isConstant() ) + return new MulFNode(in(1),new ConstantNode(TypeFloat.constant(1.0/f.value())).peephole()); return null; } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/DivNode.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/DivNode.java index 9c51b6e..82d77df 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/DivNode.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/DivNode.java @@ -1,44 +1,26 @@ package com.compilerprogramming.ezlang.compiler.nodes; -import com.compilerprogramming.ezlang.compiler.sontypes.SONType; -import com.compilerprogramming.ezlang.compiler.sontypes.SONTypeInteger; +import com.compilerprogramming.ezlang.compiler.sontypes.Type; +import com.compilerprogramming.ezlang.compiler.sontypes.TypeInteger; import java.util.BitSet; -public class DivNode extends Node { - public DivNode(Node lhs, Node rhs) { super(null, lhs, rhs); } +public class DivNode extends ArithNode { + public DivNode(Node lhs, Node rhs) { super(lhs, rhs); } @Override public String label() { return "Div"; } + @Override public String op() { return "//"; } - @Override public String glabel() { return "//"; } - - @Override - public StringBuilder _print1(StringBuilder sb, BitSet visited) { - in(1)._print0(sb.append("("), visited); - in(2)._print0(sb.append("/"), visited); - return sb.append(")"); - } - - @Override - public SONType compute() { - SONType t1 = in(1)._type, t2 = in(2)._type; - if( t1.isHigh() || t2.isHigh() ) - return SONTypeInteger.TOP; - if( t1 instanceof SONTypeInteger i1 && - t2 instanceof SONTypeInteger i2 ) { - if (i1.isConstant() && i2.isConstant()) - return i2.value() == 0 - ? SONTypeInteger.ZERO - : SONTypeInteger.constant(i1.value()/i2.value()); - } - return SONTypeInteger.BOT; + @Override long doOp( long x, long y ) { return y==0 ? 0 : x / y; } + @Override TypeInteger doOp(TypeInteger x, TypeInteger y) { + return TypeInteger.BOT; } @Override public Node idealize() { // Div of 1. - if( in(2)._type == SONTypeInteger.TRUE ) + if( in(2)._type == TypeInteger.TRUE ) return in(1); - return null; + return super.idealize(); } @Override Node copy(Node lhs, Node rhs) { return new DivNode(lhs,rhs); } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/ExternNode.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/ExternNode.java new file mode 100644 index 0000000..8f0b36d --- /dev/null +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/ExternNode.java @@ -0,0 +1,19 @@ +package com.compilerprogramming.ezlang.compiler.nodes; + +import com.compilerprogramming.ezlang.compiler.SB; +import com.compilerprogramming.ezlang.compiler.sontypes.Type; + +/** + A constant with external linkage. + */ + +public class ExternNode extends ConstantNode { + public final String _extern; + public ExternNode(Type t, String ex) { super(t); _extern = ex; } + + @Override public String label() { return "#"+_con+":"+_extern; } + @Override public String glabel() { return _con.gprint(new SB().p("#")).p(":").p(_extern).toString(); } + @Override public String uniqueName() { return "Extern_" + _nid; } + + @Override public boolean eq(Node n) { return this==n; } +} diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/FRefNode.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/FRefNode.java index 3b4a282..0b48d15 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/FRefNode.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/FRefNode.java @@ -2,7 +2,7 @@ import com.compilerprogramming.ezlang.compiler.Compiler; import com.compilerprogramming.ezlang.compiler.Var; -import com.compilerprogramming.ezlang.compiler.sontypes.SONType; +import com.compilerprogramming.ezlang.compiler.sontypes.Type; import com.compilerprogramming.ezlang.exceptions.CompilerException; import java.util.BitSet; @@ -13,7 +13,7 @@ * peepholes to the Def. */ public class FRefNode extends ConstantNode { - public static final SONType FREF_TYPE = SONType.BOTTOM; + public static final Type FREF_TYPE = Type.BOTTOM; public final Var _n; public FRefNode( Var n ) { super(FREF_TYPE); _n = n; } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/FunNode.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/FunNode.java index 7e12aaf..28cc554 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/FunNode.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/FunNode.java @@ -4,9 +4,9 @@ import com.compilerprogramming.ezlang.compiler.codegen.CodeGen; import com.compilerprogramming.ezlang.compiler.codegen.Encoding; import com.compilerprogramming.ezlang.compiler.codegen.RegMask; -import com.compilerprogramming.ezlang.compiler.sontypes.SONType; -import com.compilerprogramming.ezlang.compiler.sontypes.SONTypeFunPtr; -import com.compilerprogramming.ezlang.compiler.sontypes.SONTypeTuple; +import com.compilerprogramming.ezlang.compiler.sontypes.Type; +import com.compilerprogramming.ezlang.compiler.sontypes.TypeFunPtr; +import com.compilerprogramming.ezlang.compiler.sontypes.TypeTuple; import java.util.BitSet; import static com.compilerprogramming.ezlang.compiler.codegen.CodeGen.CODE; @@ -16,19 +16,19 @@ public class FunNode extends RegionNode { // When set true, this Call/CallEnd/Fun/Return is being trivially inlined boolean _folding; - private SONTypeFunPtr _sig; // Initial signature + private TypeFunPtr _sig; // Initial signature private ReturnNode _ret; // Return pointer public String _name; // Debug name - public FunNode(SONTypeFunPtr sig, Node... nodes ) { super(nodes); _sig = sig; } + public FunNode(TypeFunPtr sig, Node... nodes ) { super(nodes); _sig = sig; } public FunNode( FunNode fun ) { super( fun ); if( fun!=null ) { _sig = fun.sig(); _name = fun._name; } else { - _sig = SONTypeFunPtr.BOT; + _sig = TypeFunPtr.BOT; _name = ""; } } @@ -60,8 +60,8 @@ public ParmNode rpc() { public ReturnNode ret() { assert _ret!=null; return _ret; } // Signature can improve over time - public SONTypeFunPtr sig() { return _sig; } - public void setSig( SONTypeFunPtr sig ) { + public TypeFunPtr sig() { return _sig; } + public void setSig( TypeFunPtr sig ) { assert sig.isa(_sig); if( _sig != sig ) { CODE.add(this); @@ -69,10 +69,17 @@ public void setSig( SONTypeFunPtr sig ) { } } + public void setName( String name ) { + if( _name==null ) _name=name; + else _name += "."+name; + } + @Override - public SONType compute() { + public Type compute() { // Only dead if no callers after SCCP - return SONType.CONTROL; + if( unknownCallers() ) + return Type.CONTROL; + return super.compute(); } @Override @@ -87,7 +94,7 @@ public Node idealize() { } // Upgrade inferred or user-written return type to actual - if( _ret!=null && _ret._type instanceof SONTypeTuple tt && tt.ret() != _sig.ret() ) + if( _ret!=null && _ret._type instanceof TypeTuple tt && tt.ret() != _sig.ret() ) // FIXME Dibyendu //throw Utils.TODO(); return null; @@ -120,10 +127,10 @@ public Node idealize() { return _folding ? super.idepth() : CodeGen.CODE.iDepthAt(1); } // Bypass Region idom, always assume idom is Start - @Override public CFGNode idom(Node dep) { return cfg(1); } + @Override public CFGNode idom(Node dep) { return _folding && nIns()==3 ? cfg(2) : cfg(1); } // Always in-progress until we run out of unknown callers - public boolean unknownCallers() { return in(1) instanceof StartNode; } + public boolean unknownCallers() { return nIns()<2 || in(1) instanceof StartNode; } @Override public boolean inProgress() { return unknownCallers(); } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/IfNode.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/IfNode.java index 862c8b6..56ed032 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/IfNode.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/IfNode.java @@ -2,7 +2,6 @@ import com.compilerprogramming.ezlang.compiler.Utils; import com.compilerprogramming.ezlang.compiler.codegen.CodeGen; -import com.compilerprogramming.ezlang.compiler.IterPeeps; import com.compilerprogramming.ezlang.compiler.sontypes.*; import java.util.BitSet; @@ -32,25 +31,25 @@ public StringBuilder _print1(StringBuilder sb, BitSet visited) { @Override public CFGNode uctrl() { return null; } @Override - public SONType compute() { + public Type compute() { // If the If node is not reachable then neither is any following Proj - if (ctrl()._type != SONType.CONTROL && ctrl()._type != SONType.BOTTOM ) - return SONTypeTuple.IF_NEITHER; + if (ctrl()._type != Type.CONTROL && ctrl()._type != Type.BOTTOM ) + return TypeTuple.IF_NEITHER; Node pred = pred(); - SONType t = pred._type; + Type t = pred._type; // High types mean NEITHER side is reachable. // Wait until the type falls to decide which way to go. if( t.isHigh() ) - return SONTypeTuple.IF_NEITHER; + return TypeTuple.IF_NEITHER; // If constant is 0 then false branch is reachable // Else true branch is reachable if( t.isConstant() ) - return (t== SONType.NIL || t== SONTypeInteger.ZERO || (t instanceof SONTypeFunPtr tfp && tfp._fidxs==0) ) ? SONTypeTuple.IF_FALSE : SONTypeTuple.IF_TRUE; + return (t==Type.NIL || t==TypeInteger.ZERO || (t instanceof TypeFunPtr tfp && tfp._fidxs==0) ) ? TypeTuple.IF_FALSE : TypeTuple.IF_TRUE; // If adding a zero makes a difference, the predicate must not have a zero/null if( !t.makeZero().isa(t) ) - return SONTypeTuple.IF_TRUE; + return TypeTuple.IF_TRUE; - return SONTypeTuple.IF_BOTH; + return TypeTuple.IF_BOTH; } @Override diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/LoadNode.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/LoadNode.java index 4607e8e..ff9c9b7 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/LoadNode.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/LoadNode.java @@ -18,7 +18,7 @@ public class LoadNode extends MemOpNode { * @param ptr The ptr to the struct base from where we load a field * @param off The offset inside the struct base */ - public LoadNode(String name, int alias, SONType glb, Node mem, Node ptr, Node off) { + public LoadNode(String name, int alias, Type glb, Node mem, Node ptr, Node off) { super(name, alias, true, glb, mem, ptr, off); } @@ -31,10 +31,10 @@ public LoadNode(String name, int alias, SONType glb, Node mem, Node ptr, Node of public StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append(".").append(_name); } @Override - public SONType compute() { - if( mem()._type instanceof SONTypeMem mem ) { + public Type compute() { + if( mem()._type instanceof TypeMem mem ) { // Update declared forward ref to the actual - if( _declaredType.isFRef() && mem._t instanceof SONTypeMemPtr tmp && !tmp.isFRef() ) + if( _declaredType.isFRef() && mem._t instanceof TypeMemPtr tmp && !tmp.isFRef() ) _declaredType = tmp; // No lifting if ptr might null-check if( err()==null ) @@ -55,6 +55,12 @@ public Node idealize() { return extend(st.val()); } + // Simple load-after-MemMerge to a known alias can bypass. Happens when inlining. + if( mem instanceof MemMergeNode mem2 ) { + setDef(1,mem2.alias(_alias)); + return this; + } + // Simple Load-after-New on same address. if( mem instanceof ProjNode p && p.in(0) instanceof NewNode nnn && ptr == nnn.proj(1) ) // Must check same object @@ -118,7 +124,7 @@ public Node idealize() { // if( pred ) ptr.x = e0; val = pred ? e0 // else ptr.x = e1; : e1; // val = ptr.x; ptr.x = val; - if( mem() instanceof PhiNode memphi && memphi.region()._type == SONType.CONTROL && memphi.nIns()== 3 && + if( mem() instanceof PhiNode memphi && memphi.region()._type == Type.CONTROL && memphi.nIns()== 3 && // Offset can be hoisted off() instanceof ConstantNode && // Pointer can be hoisted @@ -139,8 +145,8 @@ public Node idealize() { // Load a flavored zero from a New private Node zero(NewNode nnn) { - SONTypeStruct ts = nnn._ptr._obj; - SONType zero = ts._fields[ts.findAlias(_alias)]._type.makeZero(); + TypeStruct ts = nnn._ptr._obj; + Type zero = ts._fields[ts.findAlias(_alias)]._type.makeZero(); return castRO(new ConstantNode(zero).peephole()); } @@ -179,7 +185,7 @@ private static boolean hoistPtr(Node ptr, PhiNode memphi ) { private boolean profit(PhiNode phi, int idx) { Node px = phi.in(idx); if( px==null ) return false; - if( px._type instanceof SONTypeMem mem && mem._t.isHighOrConst() ) return true; + if( px._type instanceof TypeMem mem && mem._t.isHighOrConst() ) return true; if( px instanceof StoreNode st1 && ptr()==st1.ptr() && off()==st1.off() ) return true; addDep(px); return false; @@ -195,13 +201,13 @@ private Node castRO(Node rez) { // When a load bypasses a store, the store might truncate bits - and the // load will need to zero/sign-extend. private Node extend(Node val) { - if( !(_declaredType instanceof SONTypeInteger ti) ) return val; + if( !(_declaredType instanceof TypeInteger ti) ) return val; if( ti._min==0 ) // Unsigned return new AndNode(val,con(ti._max)); // Signed extension int shift = Long.numberOfLeadingZeros(ti._max)-1; Node shf = con(shift); - if( shf._type== SONTypeInteger.ZERO ) + if( shf._type== TypeInteger.ZERO ) return val; Node shl = new ShlNode(val,shf.keep()).peephole(); return new SarNode(shl,shf.unkeep()); diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/LogicalNode.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/LogicalNode.java deleted file mode 100644 index 1b93813..0000000 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/LogicalNode.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.compilerprogramming.ezlang.compiler.nodes; - -import com.compilerprogramming.ezlang.compiler.Compiler; -import com.compilerprogramming.ezlang.compiler.sontypes.SONTypeInteger; -import com.compilerprogramming.ezlang.exceptions.CompilerException; - -import java.util.BitSet; - -public abstract class LogicalNode extends Node { - - public LogicalNode(Node lhs, Node rhs) { super(null, lhs, rhs); } - abstract String op(); - - @Override - public StringBuilder _print1(StringBuilder sb, BitSet visited) { - in(1)._print0(sb.append("("), visited); - in(2)._print0(sb.append(op()), visited); - return sb.append(")"); - } - - - @Override public CompilerException err() { - if( in(1)._type.isHigh() || in(2)._type.isHigh() ) return null; - if( !(in(1)._type instanceof SONTypeInteger) ) return Compiler.error("Cannot '"+op()+"' " + in(1)._type); - if( !(in(2)._type instanceof SONTypeInteger) ) return Compiler.error("Cannot '"+op()+"' " + in(2)._type); - return null; - } -} diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/LoopNode.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/LoopNode.java index a912ba8..088865f 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/LoopNode.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/LoopNode.java @@ -1,8 +1,8 @@ package com.compilerprogramming.ezlang.compiler.nodes; import com.compilerprogramming.ezlang.compiler.codegen.CodeGen; -import com.compilerprogramming.ezlang.compiler.sontypes.SONType; -import com.compilerprogramming.ezlang.compiler.sontypes.SONTypeMem; +import com.compilerprogramming.ezlang.compiler.sontypes.Type; +import com.compilerprogramming.ezlang.compiler.sontypes.TypeMem; public class LoopNode extends RegionNode { public LoopNode( Node entry ) { super(null,entry,null); } @@ -15,13 +15,13 @@ public class LoopNode extends RegionNode { public String label() { return "Loop"; } @Override - public SONType compute() { - if( inProgress() ) return SONType.CONTROL; + public Type compute() { + if( inProgress() ) return Type.CONTROL; return entry()._type; } // Bypass Region idom, same as the default idom() using use in(1) instead of in(0) - public int idepth() { + @Override public int idepth() { return CodeGen.CODE.validIDepth(_idepth) ? _idepth : (_idepth=CodeGen.CODE.iDepthFrom(idom().idepth())); } // Bypass Region idom, same as the default idom() using use in(1) instead of in(0) @@ -53,15 +53,15 @@ public StopNode forceExit( FunNode fun, StopNode stop ) { // Now fold control into the exit. Might have 1 valid exit, or an // XCtrl or a bunch of prior NeverNode exits. - Node top = new ConstantNode(SONType.TOP).peephole(); + Node top = new ConstantNode(Type.TOP).peephole(); Node memout = new MemMergeNode(false); memout.addDef(f); // placeholder for control for( Node u : _outputs ) - if( u instanceof PhiNode phi && phi._type.isa(SONTypeMem.BOT) ) + if( u instanceof PhiNode phi && phi._type.isa(TypeMem.BOT) ) memout.addDef(phi); Node ctrl = ret.ctrl(), mem = ret.mem(), expr = ret.expr(); - if( ctrl!=null && ctrl._type != SONType.XCONTROL ) { + if( ctrl!=null && ctrl._type != Type.XCONTROL ) { // Perfect aligned exit? if( !(ctrl instanceof RegionNode r && mem instanceof PhiNode pmem && pmem.region()==r && diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/MachConcreteNode.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/MachConcreteNode.java index 82aa6e0..f83f429 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/MachConcreteNode.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/MachConcreteNode.java @@ -1,6 +1,6 @@ package com.compilerprogramming.ezlang.compiler.nodes; -import com.compilerprogramming.ezlang.compiler.sontypes.SONType; +import com.compilerprogramming.ezlang.compiler.sontypes.Type; import com.compilerprogramming.ezlang.compiler.Utils; import java.util.BitSet; @@ -13,7 +13,7 @@ public abstract class MachConcreteNode extends Node implements MachNode { public MachConcreteNode(Node[]nodes) { super(nodes); } @Override public String label() { return op(); } - @Override public SONType compute () { throw Utils.TODO(); } + @Override public Type compute () { throw Utils.TODO(); } @Override public Node idealize() { throw Utils.TODO(); } @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) { diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/MemMergeNode.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/MemMergeNode.java index 6a36e74..ee69554 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/MemMergeNode.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/MemMergeNode.java @@ -18,7 +18,7 @@ public class MemMergeNode extends Node { */ public final boolean _inProgress; - public MemMergeNode( boolean inProgress) { _type = SONTypeMem.BOT; _inProgress = inProgress; } + public MemMergeNode( boolean inProgress) { _type = TypeMem.BOT; _inProgress = inProgress; } public MemMergeNode(MemMergeNode mem) { super(mem); _inProgress = false; } @@ -54,34 +54,49 @@ public Node merge() { MemMergeNode merge = new MemMergeNode(false); for( Node n : _inputs ) merge.addDef(n); - merge._mem(1,null); + for( int i=1; i=nIns() || in(i)==null ) + setDefX(i,mem.in(i)); + } + } + setDef(1,mem.in(1)); + return this; + } + + return progress ? this : null; } public Node in( Var v ) { return in(v._idx); } public Node alias( int alias ) { - return in(alias _outputs; + public Ary _outputs; /** * Current computed type for this Node. This value changes as the graph * changes and more knowledge is gained about the program. */ - public SONType _type; + public Type _type; Node(Node... inputs) { @@ -67,11 +67,11 @@ public abstract class Node implements Cloneable { // Make a Node using the existing arrays of nodes. // Used by any pass rewriting all Node classes but not the edges. Node( Node n ) { - assert CodeGen.CODE._phase.ordinal() >= CodeGen.Phase.InstSelect.ordinal(); + assert CodeGen.CODE._phase.ordinal() >= CodeGen.Phase.Select.ordinal(); _nid = CODE.getUID(); // allocate unique dense ID _inputs = new Ary<>(n==null ? new Node[0] : n._inputs.asAry()); _outputs = new Ary<>(Node.class); - _type = n==null ? SONType.BOTTOM : n._type; + _type = n==null ? Type.BOTTOM : n._type; _deps = null; _hash = 0; } @@ -240,7 +240,7 @@ protected boolean delUse( Node use ) { // Shortcut for "popping" until n nodes. A "pop" is basically a // setDef(last,null) followed by lowering the nIns() count. - void popUntil(int n) { + public void popUntil(int n) { unlock(); while( nIns() > n ) { Node old_def = _inputs.pop(); @@ -256,9 +256,9 @@ void popUntil(int n) { * code elimination. */ public void kill( ) { + assert isUnused(); // Has no uses, so it is dead unlock(); moveDepsToWorklist(); - assert isUnused(); // Has no uses, so it is dead _type=null; // Flag as dead while( nIns()>0 ) { // Set all inputs to null, recursively killing unused Nodes Node old_def = _inputs.removeLast(); @@ -296,6 +296,10 @@ public void unkill() { if( unkeep().isUnused() ) kill(); } + public void isKill() { + if( isUnused() ) + kill(); + } // Replace self with nnn in the graph, making 'this' go dead @@ -386,9 +390,9 @@ public final Node peephole( ) { /** * Try to peephole at this node and return a better replacement Node if - * possible. We compute a {@link SONType} and then check and replace: + * possible. We compute a {@link Type} and then check and replace: *
    - *
  • if the Type {@link SONType#isConstant}, we replace with a {@link ConstantNode}
  • + *
  • if the Type {@link Type#isConstant}, we replace with a {@link ConstantNode}
  • *
  • in a future chapter we will look for a * Common Subexpression * to eliminate.
  • @@ -405,7 +409,7 @@ public final Node peephole( ) { public final Node peepholeOpt( ) { CODE.iterCnt(); // Compute initial or improved Type - SONType old = setType(compute()); + Type old = setType(compute()); // Replace constant computations from non-constants with a constant // node. If peeps are disabled, still allow high Phis to collapse; @@ -473,12 +477,12 @@ private Node deadCodeElim(Node m) { * infinitely recurse until stack overflow. Instead, compute typically * computes a new type from the {@link #_type} field of its inputs. */ - public abstract SONType compute(); + public abstract Type compute(); // Set the type. Assert monotonic progress. // If changing, add users to worklist. - public SONType setType(SONType type) { - SONType old = _type; + public Type setType(Type type) { + Type old = _type; assert old==null || type.isa(old); // Since _type not set, can just re-run this in assert in the debugger if( old == type ) return old; _type = type; // Set _type late for easier assert debugging @@ -634,13 +638,13 @@ public final Node widen() { Node flt = copyF(); if( flt==null ) return this; for( int i=1; i 0 || i._max < 0) ) return SONTypeInteger.FALSE; - return SONTypeInteger.BOOL; + public TypeInteger compute() { + Type t0 = in(1)._type; + if( t0.isHigh() ) return TypeInteger.BOOL.dual(); + if( t0 == Type.NIL || t0 == TypeInteger.ZERO ) return TypeInteger.TRUE; + if( t0 instanceof TypeNil tn && tn.notNull() ) return TypeInteger.FALSE; + if( t0 instanceof TypeInteger i && (i._min > 0 || i._max < 0) ) return TypeInteger.FALSE; + return TypeInteger.BOOL; } @Override diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/OrNode.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/OrNode.java index fc76f23..211090f 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/OrNode.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/OrNode.java @@ -1,40 +1,31 @@ package com.compilerprogramming.ezlang.compiler.nodes; -import com.compilerprogramming.ezlang.compiler.Compiler; -import com.compilerprogramming.ezlang.compiler.sontypes.SONType; -import com.compilerprogramming.ezlang.compiler.sontypes.SONTypeInteger; +import com.compilerprogramming.ezlang.compiler.sontypes.Type; +import com.compilerprogramming.ezlang.compiler.sontypes.TypeInteger; -public class OrNode extends LogicalNode { +public class OrNode extends ArithNode { public OrNode(Node lhs, Node rhs) { super(lhs, rhs); } @Override public String label() { return "Or"; } @Override public String op() { return "|"; } - @Override public String glabel() { return "|"; } - @Override - public SONType compute() { - SONType t1 = in(1)._type, t2 = in(2)._type; - if( t1.isHigh() || t2.isHigh() ) - return SONTypeInteger.TOP; - if( t1 instanceof SONTypeInteger i0 && - t2 instanceof SONTypeInteger i1 ) { - if( i0.isConstant() && i1.isConstant() ) - return SONTypeInteger.constant(i0.value()|i1.value()); - } - return SONTypeInteger.BOT; + + @Override long doOp( long x, long y ) { return x | y; } + @Override TypeInteger doOp(TypeInteger x, TypeInteger y) { + return TypeInteger.BOT; } @Override public Node idealize() { Node lhs = in(1); Node rhs = in(2); - SONType t1 = lhs._type; - SONType t2 = rhs._type; + Type t1 = lhs._type; + Type t2 = rhs._type; // Or of 0. We do not check for (0|x) because this will already // canonicalize to (x|0) - if( t2.isConstant() && t2 instanceof SONTypeInteger i && i.value()==0 ) + if( t2.isConstant() && t2 instanceof TypeInteger i && i.value()==0 ) return lhs; // Move constants to RHS: con*arg becomes arg*con @@ -47,7 +38,7 @@ public Node idealize() { Node phicon = AddNode.phiCon(this,true); if( phicon!=null ) return phicon; - return null; + return super.idealize(); } @Override Node copy(Node lhs, Node rhs) { return new OrNode(lhs,rhs); } } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/ParmNode.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/ParmNode.java index b755949..efc6903 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/ParmNode.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/ParmNode.java @@ -1,6 +1,6 @@ package com.compilerprogramming.ezlang.compiler.nodes; -import com.compilerprogramming.ezlang.compiler.sontypes.SONType; +import com.compilerprogramming.ezlang.compiler.sontypes.Type; import java.util.BitSet; public class ParmNode extends PhiNode { @@ -8,7 +8,7 @@ public class ParmNode extends PhiNode { // Argument indices are mapped one-to-one on CallNode inputs public final int _idx; // Argument index - public ParmNode(String label, int idx, SONType declaredType, Node... inputs) { + public ParmNode(String label, int idx, Type declaredType, Node... inputs) { super(label,declaredType,inputs); _idx = idx; } @@ -44,4 +44,8 @@ public Node idealize() { // Always in-progress until we run out of unknown callers @Override public boolean inProgress() { return fun().inProgress(); } + + @Override public boolean eq( Node n ) { + return ((ParmNode)n)._idx==_idx && super.eq(n); + } } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/PhiNode.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/PhiNode.java index 9ac7bb8..b48fa25 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/PhiNode.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/PhiNode.java @@ -11,10 +11,10 @@ public class PhiNode extends Node { // The Phi type we compute must stay within the domain of the Phi. // Example Int stays Int, Ptr stays Ptr, Control stays Control, Mem stays Mem. - final SONType _declaredType; + final Type _declaredType; - public PhiNode(String label, SONType declaredType, Node... inputs) { super(inputs); _label = label; assert declaredType!=null; _declaredType = declaredType; } - public PhiNode(PhiNode phi, String label, SONType declaredType) { super(phi); _label = label; _type = _declaredType = declaredType; } + public PhiNode(String label, Type declaredType, Node... inputs) { super(inputs); _label = label; assert declaredType!=null; _declaredType = declaredType; } + public PhiNode(PhiNode phi, String label, Type declaredType) { super(phi); _label = label; _type = _declaredType = declaredType; } public PhiNode(PhiNode phi) { super(phi); _label = phi._label; _declaredType = phi._declaredType; } public PhiNode(RegionNode r, Node sample) { @@ -45,21 +45,21 @@ public StringBuilder _print1(StringBuilder sb, BitSet visited) { } public CFGNode region() { return (CFGNode)in(0); } - @Override public boolean isMem() { return _declaredType instanceof SONTypeMem; } + @Override public boolean isMem() { return _declaredType instanceof TypeMem; } @Override public boolean isPinned() { return true; } @Override - public SONType compute() { + public Type compute() { if( !(region() instanceof RegionNode r) ) - return region()._type== SONType.XCONTROL ? (_type instanceof SONTypeMem ? SONTypeMem.TOP : SONType.TOP) : _type; + return region()._type==Type.XCONTROL ? (_type instanceof TypeMem ? TypeMem.TOP : Type.TOP) : _type; // During parsing Phis have to be computed type pessimistically. if( r.inProgress() ) return _declaredType; // Set type to local top of the starting type - SONType t = _declaredType.glb().dual();//Type.TOP; + Type t = _declaredType.glb(false).dual();//Type.TOP; for (int i = 1; i < nIns(); i++) // If the region's control input is live, add this as a dependency // to the control because we can be peeped should it become dead. - if( addDep(r.in(i))._type != SONType.XCONTROL ) + if( addDep(r.in(i))._type != Type.XCONTROL ) t = t.meet(in(i)._type); return t; } @@ -78,7 +78,7 @@ public Node idealize() { // No bother if region is going to fold dead paths soon for( int i=1; i 1 ) { // Too many users, but addDep in case lose users for( Node out : op._outputs ) if( out!=null && out!=this ) addDep(out); return false; } + for( int j=1; j>"; } - @Override public String glabel() { return ">>"; } - @Override - public SONType compute() { - SONType t1 = in(1)._type, t2 = in(2)._type; - if( t1.isHigh() || t2.isHigh() ) - return SONTypeInteger.TOP; - if (t1 instanceof SONTypeInteger i0 && - t2 instanceof SONTypeInteger i1) { - if( i0 == SONTypeInteger.ZERO ) - return SONTypeInteger.ZERO; - if( i0.isConstant() && i1.isConstant() ) - return SONTypeInteger.constant(i0.value()>>i1.value()); - if( i1.isConstant() ) { - int log = (int)i1.value(); - return SONTypeInteger.make(-1L<<(63-log),(1L<<(63-log))-1); - } + @Override long doOp( long x, long y ) { return x >> y; } + @Override TypeInteger doOp( TypeInteger x, TypeInteger y ) { + if( y.isConstant() ) { + int log = (int)y.value(); + return TypeInteger.make(-1L<<(63-log),(1L<<(63-log))-1); } - return SONTypeInteger.BOT; + return TypeInteger.BOT; } @Override public Node idealize() { Node lhs = in(1); Node rhs = in(2); - SONType t2 = rhs._type; + Type t2 = rhs._type; // Sar of 0. - if( t2.isConstant() && t2 instanceof SONTypeInteger i && (i.value()&63)==0 ) + if( t2.isConstant() && t2 instanceof TypeInteger i && (i.value()&63)==0 ) return lhs; // TODO: x >> 3 >> (y ? 1 : 2) ==> x >> (y ? 4 : 5) - return null; + return super.idealize(); } @Override Node copy(Node lhs, Node rhs) { return new SarNode(lhs,rhs); } } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/ScopeNode.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/ScopeNode.java index c3109cc..525acd3 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/ScopeNode.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/ScopeNode.java @@ -49,7 +49,7 @@ public StringBuilder _print1(StringBuilder sb, BitSet visited) { int j=1; for( int i=0; i N ctrl(N n) { return setDef(0,n); } public Node mem(Node n) { return setDef(1,n); } - public void push(Kind kind) { + public void push( Kind kind ) { assert _lexSize._len==_kinds._len; _lexSize.push(_vars.size()); _kinds .push(kind); @@ -94,11 +95,11 @@ public void push(Kind kind) { // Pop a lexical scope public void pop() { assert _lexSize._len==_kinds._len; - promote(); + promote(); // Promote forward references to the next outer scope int n = _lexSize.pop(); _kinds.pop(); - popUntil(n); - _vars.setLen(n); + popUntil(n); // Pop off inputs going out of scope + _vars.setLen(n); // Pop off variables going out of scope } @@ -107,7 +108,7 @@ public void pop() { public void promote() { int n = _lexSize.last(); for( int i=n; i=0; i-- ) - if( _vars.at(i)._name.equals(name) ) + if( var(i)._name.equals(name) ) return i; return -1; } @@ -144,11 +145,11 @@ int find( String name ) { /** * Create a new variable name in the current scope */ - public boolean define(String name, SONType declaredType, boolean xfinal, Node init) { + public boolean define(String name, Type declaredType, boolean xfinal, Node init) { assert _lexSize.isEmpty() || name.charAt(0)!='$' ; // Later scopes do not define memory if( _lexSize._len > 0 ) for( int i=_vars.size()-1; i>=_lexSize.last(); i-- ) { - Var n = _vars.at(i); + Var n = var(i); if( n._name.equals(name) ) { if( !n.isFRef() ) return false; // Double define FRefNode fref = (FRefNode)in(n._idx); // Get forward ref @@ -181,11 +182,11 @@ public boolean define(String name, SONType declaredType, boolean xfinal, Node in public Var lookup( String name ) { int idx = find(name); // -1 is missed in all scopes, not found - return idx == -1 ? null : update(_vars.at(idx),null); + return idx == -1 ? null : update(var(idx),null); } /** - * If the name is present in any scope, then redefine else null + * Redefine an existing name * * @param name Name being redefined * @param n The node to bind to the name @@ -193,7 +194,7 @@ public Var lookup( String name ) { public void update( String name, Node n ) { int idx = find(name); assert idx>=0; - update(_vars.at(idx),n); + update(var(idx),n); } public Var update( Var v, Node st ) { @@ -207,7 +208,7 @@ public Var update( Var v, Node st ) { // Set real Phi in the loop head // The phi takes its one input (no backedge yet) from a recursive // lookup, which might have insert a Phi in every loop nest. - : loop.setDef(v._idx,new PhiNode(v._name, v.lazyGLB(), loop.ctrl(), loop.in(loop.update(v,null)._idx),null).peephole()); + : loop.setDef(v._idx,new PhiNode(v._name, v.type(), loop.ctrl(), loop.in(loop.update(v,null)._idx),null).peephole()); setDef(v._idx,old); } assert !v._final || st==null; @@ -260,7 +261,7 @@ public ScopeNode dup(boolean loop) { for( int i=2; i>shf) != x._min || + ((x._max<>shf) != x._max ) ) + return TypeInteger.make(x._min< (x << i) + (c << i) - if( lhs instanceof AddNode add && addDep(add).in(2)._type instanceof SONTypeInteger c && c.isConstant() ) { + if( lhs instanceof AddNode add && addDep(add).in(2)._type instanceof TypeInteger c && c.isConstant() ) { long sum = c.value() << shl.value(); if( Integer.MIN_VALUE <= sum && sum <= Integer.MAX_VALUE ) return new AddNode(new ShlNode(add.in(1),rhs).peephole(), Compiler.con(sum) ); @@ -46,7 +44,7 @@ public Node idealize() { // TODO: x << 3 << (y ? 1 : 2) ==> x << (y ? 4 : 5) - return null; + return super.idealize(); } @Override Node copy(Node lhs, Node rhs) { return new ShlNode(lhs,rhs); } } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/ShrNode.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/ShrNode.java index c4b2a9b..2fb8aad 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/ShrNode.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/ShrNode.java @@ -1,45 +1,33 @@ package com.compilerprogramming.ezlang.compiler.nodes; -import com.compilerprogramming.ezlang.compiler.Compiler; -import com.compilerprogramming.ezlang.compiler.sontypes.SONType; -import com.compilerprogramming.ezlang.compiler.sontypes.SONTypeInteger; +import com.compilerprogramming.ezlang.compiler.sontypes.Type; +import com.compilerprogramming.ezlang.compiler.sontypes.TypeInteger; -public class ShrNode extends LogicalNode { +public class ShrNode extends ArithNode { public ShrNode(Node lhs, Node rhs) { super(lhs, rhs); } @Override public String label() { return "Shr"; } @Override public String op() { return ">>>"; } - @Override public String glabel() { return ">>>"; } - @Override - public SONType compute() { - SONType t1 = in(1)._type, t2 = in(2)._type; - if( t1.isHigh() || t2.isHigh() ) - return SONTypeInteger.TOP; - if (t1 instanceof SONTypeInteger i0 && - t2 instanceof SONTypeInteger i1 ) { - if( i0 == SONTypeInteger.ZERO ) - return SONTypeInteger.ZERO; - if( i0.isConstant() && i1.isConstant() ) - return SONTypeInteger.constant(i0.value()>>>i1.value()); - } - return SONTypeInteger.BOT; + @Override long doOp( long x, long y ) { return x >>> y; } + @Override TypeInteger doOp( TypeInteger x, TypeInteger y ) { + return x == TypeInteger.ZERO ? x : TypeInteger.BOT; } @Override public Node idealize() { Node lhs = in(1); Node rhs = in(2); - SONType t2 = rhs._type; + Type t2 = rhs._type; // Shr of 0. - if( t2.isConstant() && t2 instanceof SONTypeInteger i && (i.value()&63)==0 ) + if( t2.isConstant() && t2 instanceof TypeInteger i && (i.value()&63)==0 ) return lhs; // TODO: x >>> 3 >>> (y ? 1 : 2) ==> x >>> (y ? 4 : 5) - return null; + return super.idealize(); } @Override Node copy(Node lhs, Node rhs) { return new ShrNode(lhs,rhs); } } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/SplitNode.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/SplitNode.java index 0040146..f233e5f 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/SplitNode.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/SplitNode.java @@ -2,7 +2,7 @@ import com.compilerprogramming.ezlang.compiler.SB; import com.compilerprogramming.ezlang.compiler.codegen.CodeGen; -import com.compilerprogramming.ezlang.compiler.sontypes.SONType; +import com.compilerprogramming.ezlang.compiler.sontypes.Type; import java.util.BitSet; public abstract class SplitNode extends MachConcreteNode { @@ -16,7 +16,7 @@ public abstract class SplitNode extends MachConcreteNode { else in(1)._print0(sb,visited); return sb.append(")"); } - @Override public SONType compute() { return in(0)._type; } + @Override public Type compute() { return in(0)._type; } @Override public Node idealize() { return null; } @Override public void asm(CodeGen code, SB sb) { sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))); diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/StartNode.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/StartNode.java index 5908301..b03a3a4 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/StartNode.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/StartNode.java @@ -1,7 +1,6 @@ package com.compilerprogramming.ezlang.compiler.nodes; import com.compilerprogramming.ezlang.compiler.codegen.CodeGen; -import com.compilerprogramming.ezlang.compiler.Compiler; import com.compilerprogramming.ezlang.compiler.sontypes.*; import java.util.BitSet; @@ -17,9 +16,9 @@ */ public class StartNode extends LoopNode implements MultiNode { - final SONType _arg; + final Type _arg; - public StartNode(SONType arg) { super((Node)null); _arg = arg; _type = compute(); } + public StartNode(Type arg) { super((Node)null); _arg = arg; _type = compute(); } public StartNode(StartNode start) { super(start); _arg = start==null ? null : start._arg; } @Override public String label() { return "Start"; } @@ -44,8 +43,8 @@ public StringBuilder _print1(StringBuilder sb, BitSet visited) { } - @Override public SONTypeTuple compute() { - return SONTypeTuple.make(SONType.CONTROL, SONTypeMem.TOP,_arg); + @Override public TypeTuple compute() { + return TypeTuple.make(Type.CONTROL,TypeMem.TOP,_arg); } @Override public Node idealize() { return null; } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/StopNode.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/StopNode.java index f0fbdfa..9dcc8e3 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/StopNode.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/StopNode.java @@ -1,6 +1,6 @@ package com.compilerprogramming.ezlang.compiler.nodes; -import com.compilerprogramming.ezlang.compiler.sontypes.SONType; +import com.compilerprogramming.ezlang.compiler.sontypes.Type; import java.util.BitSet; public class StopNode extends CFGNode { @@ -22,11 +22,15 @@ public String label() { @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) { // For the sake of many old tests, and single value prints as "return val" - if( ret()!=null ) return ret()._print0(sb,visited); + ReturnNode ret1 = ret(); + if( ret1!=null ) return ret1._print0(sb,visited); sb.append("Stop[ "); for( Node ret : _inputs ) - if( ret!=null ) - ret._print0(sb, visited).append(" "); + if( ret!=null ) { + String name = ((ReturnNode)ret).fun()._name; + if( name== null || !name.startsWith("sys.") ) + ret._print0(sb, visited).append(" "); + } return sb.append("]"); } @@ -36,19 +40,25 @@ public StringBuilder _print1(StringBuilder sb, BitSet visited) { // If a single Return, return it. // Otherwise, null because ambiguous. public ReturnNode ret() { - return nIns()==1 && in(0) instanceof ReturnNode ret ? ret : null; + Node ret1 = this; + for( Node ret : _inputs ) { + String name = ((ReturnNode)ret).fun()._name; + if( name==null || !name.startsWith("sys.") ) + ret1 = ret1==this ? ((ReturnNode)ret) : null; + } + return ret1==this ? null : (ReturnNode)ret1; } @Override - public SONType compute() { - return SONType.BOTTOM; + public Type compute() { + return Type.BOTTOM; } @Override public Node idealize() { int len = nIns(); for( int i=0; i= store_size && not_affected_bits >= store_size) { + setDef(4, shl.in(1)); + return this; + } + } return null; } @@ -110,10 +127,10 @@ private boolean checkOnlyUse(Node mem) { public CompilerException err() { CompilerException err = super.err(); if( err != null ) return err; - SONTypeMemPtr tmp = (SONTypeMemPtr)ptr()._type; + TypeMemPtr tmp = (TypeMemPtr)ptr()._type; if( tmp._obj.field(_name)._final && !_init ) return Compiler.error("Cannot modify final field '"+_name+"'"); - SONType t = val()._type; + Type t = val()._type; //return _init || t.isa(_declaredType) ? null : Parser.error("Cannot store "+t+" into field "+_declaredType+" "+_name,_loc); return null; } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/StructNode.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/StructNode.java index 71f3bb2..82746b2 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/StructNode.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/StructNode.java @@ -9,7 +9,7 @@ */ public class StructNode extends Node { - public SONTypeStruct _ts; + public TypeStruct _ts; @Override public String label() { return _ts==null ? "STRUCT?" : _ts.str(); } @@ -19,7 +19,7 @@ public StringBuilder _print1(StringBuilder sb, BitSet visited) { sb.append(_ts._name).append(" {"); for( int i=0; i> 12; // patch upper 20 bits via adrp enc.patch4(opStart, arm.adrp(1, adrp_delta & 0b11, 0b10000, adrp_delta >> 2, rpc)); // low 12 bits via add - enc.patch4(next, arm.imm_inst_l(arm.OPI_ADD, delta & 0xfff, rpc)); + enc.patch4(opStart+4, arm.imm_inst_l(arm.OPI_ADD, delta & 0xfff, rpc)); } else { // should not happen as one instruction is 4 byte, and TFP arm encodes 2. throw Utils.TODO(); @@ -50,4 +50,5 @@ public class TFPARM extends ConstantNode implements MachNode, RIPRelSize { String reg = code.reg(this); _con.print(sb.p(reg).p(" #")); } + @Override public boolean eq(Node n) { return this==n; } } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/TMPARM.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/TMPARM.java new file mode 100644 index 0000000..0356677 --- /dev/null +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/TMPARM.java @@ -0,0 +1,53 @@ +package com.compilerprogramming.ezlang.compiler.nodes.cpus.arm; + +import com.compilerprogramming.ezlang.compiler.*; +import com.compilerprogramming.ezlang.compiler.codegen.*; +import com.compilerprogramming.ezlang.compiler.nodes.ConstantNode; +import com.compilerprogramming.ezlang.compiler.nodes.MachNode; +import com.compilerprogramming.ezlang.compiler.nodes.Node; +import com.compilerprogramming.ezlang.compiler.sontypes.TypeMemPtr; + +public class TMPARM extends ConstantNode implements MachNode, RIPRelSize { + TMPARM( ConstantNode con ) { super(con); } + @Override public String op() { return "ldp"; } + @Override public RegMask regmap(int i) { return null; } + @Override public RegMask outregmap() { return arm.WMASK; } + @Override public boolean isClone() { return true; } + @Override public TMPARM copy() { return new TMPARM(this); } + @Override public void encoding( Encoding enc ) { + enc.largeConstant(this,((TypeMemPtr)_con)._obj,0,-1); + short dst = enc.reg(this); + // adrp x0, 0 + enc.add4(arm.adrp(1,0, arm.OP_ADRP, 0,dst)); + // add x0, x0, 0 + arm.imm_inst(enc,arm.OPI_ADD,0, dst); + } + + @Override public byte encSize(int delta) { + return 8; + } + + // Delta is from opcode start + @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { + short dst = enc.reg(this); + if(opLen == 8 ) { + // ARM encoding delta is from PC & 0xFFF + int target = opStart+delta; + int base = opStart & ~0xFFF; + delta = target-base; + int adrp_delta = delta >> 12; + // patch upper 20 bits via adrp + enc.patch4(opStart, arm.adrp(1, adrp_delta & 0b11, 0b10000, adrp_delta >> 2, dst)); + // low 12 bits via add + enc.patch4(opStart+4, arm.imm_inst_l(arm.OPI_ADD, delta & 0xfff, dst)); + } else { + throw Utils.TODO(); + } + } + + @Override public void asm(CodeGen code, SB sb) { + String reg = code.reg(this); + _con.print(sb.p(reg).p(" #")); + } + @Override public boolean eq(Node n) { return this==n; } +} diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/UJmpARM.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/UJmpARM.java index 6405475..fa1dfab 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/UJmpARM.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/UJmpARM.java @@ -3,7 +3,7 @@ import com.compilerprogramming.ezlang.compiler.*; import com.compilerprogramming.ezlang.compiler.codegen.*; import com.compilerprogramming.ezlang.compiler.nodes.*; -import com.compilerprogramming.ezlang.compiler.sontypes.SONType; +import com.compilerprogramming.ezlang.compiler.sontypes.Type; import java.util.BitSet; // unconditional jump @@ -16,7 +16,7 @@ public class UJmpARM extends CFGNode implements MachNode, RIPRelSize { } @Override public RegMask regmap(int i) {return null; } @Override public RegMask outregmap() { return null; } - @Override public SONType compute() { throw Utils.TODO(); } + @Override public Type compute() { throw Utils.TODO(); } @Override public Node idealize() { throw Utils.TODO(); } @Override public void encoding( Encoding enc ) { enc.jump(this,uctrl()); diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/arm.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/arm.java index e9b6644..cf541f7 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/arm.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/arm.java @@ -252,12 +252,12 @@ public enum COND { } // True if signed 9-bit immediate - private static boolean imm9(SONTypeInteger ti) { + private static boolean imm9(TypeInteger ti) { // 55 = 64-9 return ti.isConstant() && ((ti.value()<<55)>>55) == ti.value(); } // True if signed 12-bit immediate - private static boolean imm12(SONTypeInteger ti) { + private static boolean imm12(TypeInteger ti) { // 52 = 64-12 return ti.isConstant() && ((ti.value()<<52)>>52) == ti.value(); } @@ -265,7 +265,7 @@ private static boolean imm12(SONTypeInteger ti) { // Can we encode this in ARM's 12-bit LOGICAL immediate form? // Some combination of shifted bit-masks. - private static int imm12Logical(SONTypeInteger ti) { + private static int imm12Logical(TypeInteger ti) { if( !ti.isConstant() ) return -1; if( !ti.isConstant() ) return -1; long val = ti.value(); @@ -563,17 +563,19 @@ public static int b_calloc(int opcode, int delta) { return (opcode << 26) | delta; } - @Override public RegMask callArgMask(SONTypeFunPtr tfp, int idx, int maxArgSlot ) { return callInMask(tfp,idx,maxArgSlot); } - static RegMask callInMask(SONTypeFunPtr tfp, int idx, int maxArgSlot ) { + @Override public RegMask callArgMask(TypeFunPtr tfp, int idx, int maxArgSlot ) { return callInMask(tfp,idx,maxArgSlot); } + static RegMask callInMask(TypeFunPtr tfp, int idx, int maxArgSlot ) { if( idx==0 ) return CodeGen.CODE._rpcMask; if( idx==1 ) return null; // Count floats in signature up to index + if( idx-2 >= tfp.nargs() ) return null; // Anti-dependence + // Count floats in signature up to index int fcnt=0; for( int i=2; i new AddFARM(addf); - case AddNode add -> add(add); - case AndNode and -> and(and); - case BoolNode bool -> cmp(bool); - case CallNode call -> call(call); - case CastNode cast -> new CastARM(cast); - case CallEndNode cend -> new CallEndARM(cend); - case CProjNode c -> new CProjNode(c); - case ConstantNode con -> con(con); - case DivFNode divf -> new DivFARM(divf); - case DivNode div -> new DivARM(div); - case FunNode fun -> new FunARM(fun); - case IfNode iff -> jmp(iff); - case LoadNode ld -> ld(ld); - case MemMergeNode mem -> new MemMergeNode(mem); - case MinusNode neg -> new NegARM(neg); - case MulFNode mulf -> new MulFARM(mulf); - case MulNode mul -> new MulARM(mul); - case NewNode nnn -> new NewARM(nnn); - case NotNode not -> new NotARM(not); - case OrNode or -> or(or); - case ParmNode parm -> new ParmARM(parm); - case PhiNode phi -> new PhiNode(phi); - case ProjNode prj -> new ProjARM(prj); - case ReadOnlyNode read -> new ReadOnlyNode(read); - case ReturnNode ret -> new RetARM(ret,ret.fun()); - case SarNode sar -> asr(sar); - case ShlNode shl -> lsl(shl); - case ShrNode shr -> lsr(shr); + case AddFNode addf -> new AddFARM(addf); + case AddNode add -> add(add); + case AndNode and -> and(and); + case BoolNode bool -> cmp(bool); + case CallNode call -> call(call); + case CastNode cast -> new CastMach(cast); + case CallEndNode cend-> new CallEndMach(cend); + case CProjNode c -> new CProjNode(c); + case ConstantNode con-> con(con); + case DivFNode divf -> new DivFARM(divf); + case DivNode div -> new DivARM(div); + case FunNode fun -> new FunARM(fun); + case IfNode iff -> jmp(iff); + case LoadNode ld -> ld(ld); + case MemMergeNode mem-> new MemMergeNode(mem); + case MinusNode neg -> new NegARM(neg); + case MulFNode mulf -> new MulFARM(mulf); + case MulNode mul -> new MulARM(mul); + case NewNode nnn -> new NewARM(nnn); + case NotNode not -> new NotARM(not); + case OrNode or -> or(or); + case ParmNode parm -> new ParmARM(parm); + case PhiNode phi -> new PhiNode(phi); + case ProjNode prj -> new ProjARM(prj); + case ReadOnlyNode read -> new ReadOnlyMach(read); + case ReturnNode ret -> new RetARM(ret,ret.fun()); + case SarNode sar -> asr(sar); + case ShlNode shl -> lsl(shl); + case ShrNode shr -> lsr(shr); case StartNode start -> new StartNode(start); - case StopNode stop -> new StopNode(stop); - case StoreNode st -> st(st); - case SubFNode subf -> new SubFARM(subf); - case SubNode sub -> sub(sub); - case ToFloatNode tfn-> new I2F8ARM(tfn); - case XorNode xor -> xor(xor); - - case LoopNode loop -> new LoopNode(loop); + case StopNode stop -> new StopNode(stop); + case StoreNode st -> st(st); + case SubFNode subf -> new SubFARM(subf); + case SubNode sub -> sub(sub); + case ToFloatNode tfn -> new I2F8ARM(tfn); + case XorNode xor -> xor(xor); + + case LoopNode loop -> new LoopNode(loop); case RegionNode region-> new RegionNode(region); default -> throw Utils.TODO(); }; @@ -694,7 +696,7 @@ private Node cmp(BoolNode bool){ private Node _cmp(BoolNode bool) { if( bool.isFloat() ) return new CmpFARM(bool); - return bool.in(2) instanceof ConstantNode con && con._con instanceof SONTypeInteger ti + return bool.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti ? new CmpIARM(bool, (int)ti.value()) : new CmpARM(bool); } @@ -710,18 +712,18 @@ private Node jmp(IfNode iff) { String op = "!="; if( iff.in(1) instanceof BoolNode bool ) op = bool.op(); else if( iff.in(1)==null ) op = "=="; // Never-node cutout - else iff.setDef(1, new BoolNode.NE(iff.in(1), new ConstantNode(SONTypeInteger.ZERO))); + else iff.setDef(1, new BoolNode.NE(iff.in(1), new ConstantNode(TypeInteger.ZERO))); return new BranchARM(iff, op); } private Node add(AddNode add) { - return add.in(2) instanceof ConstantNode off && off._con instanceof SONTypeInteger ti && imm12(ti) + return add.in(2) instanceof ConstantNode off && off._con instanceof TypeInteger ti && imm12(ti) ? new AddIARM(add, (int)ti.value()) : new AddARM(add); } private Node sub(SubNode sub) { - return sub.in(2) instanceof ConstantNode con && con._con instanceof SONTypeInteger ti && imm12(ti) + return sub.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm12(ti) ? new SubIARM(sub, (int)(ti.value())) : new SubARM(sub); } @@ -729,57 +731,57 @@ private Node sub(SubNode sub) { private Node con( ConstantNode con ) { if( !con._con.isConstant() ) return new ConstantNode( con ); // Default unknown caller inputs return switch( con._con ) { - case SONTypeInteger ti -> new IntARM(con); - case SONTypeFloat tf -> new FloatARM(con); - case SONTypeFunPtr tfp -> new TFPARM(con); - case SONTypeMemPtr tmp -> new ConstantNode(con); - case SONTypeNil tn -> throw Utils.TODO(); - // TOP, BOTTOM, XCtrl, Ctrl, etc. Never any executable code. - case SONType t -> t==SONType.NIL ? new IntARM(con) : new ConstantNode(con); + case TypeInteger ti -> new IntARM(con); + case TypeFloat tf -> new FloatARM(con); + case TypeFunPtr tfp -> new TFPARM(con); + case TypeMemPtr tmp -> new TMPARM(con); + case TypeNil tn -> throw Utils.TODO(); + // TOP, BOTTOM, XCtrl, Ctrl, etc. Never any executable code. + case Type t -> t==Type.NIL ? new IntARM(con) : new ConstantNode(con); }; } private Node call(CallNode call){ - return call.fptr() instanceof ConstantNode con && con._con instanceof SONTypeFunPtr tfp + return call.fptr() instanceof ConstantNode con && con._con instanceof TypeFunPtr tfp ? new CallARM(call, tfp) : new CallRRARM(call); } private Node or(OrNode or) { int imm12; - return or.in(2) instanceof ConstantNode off && off._con instanceof SONTypeInteger ti && (imm12 = imm12Logical(ti)) != -1 + return or.in(2) instanceof ConstantNode off && off._con instanceof TypeInteger ti && (imm12 = imm12Logical(ti)) != -1 ? new OrIARM(or, imm12) : new OrARM(or); } private Node xor(XorNode xor) { int imm12; - return xor.in(2) instanceof ConstantNode off && off._con instanceof SONTypeInteger ti && (imm12 = imm12Logical(ti)) != -1 + return xor.in(2) instanceof ConstantNode off && off._con instanceof TypeInteger ti && (imm12 = imm12Logical(ti)) != -1 ? new XorIARM(xor, imm12) : new XorARM(xor); } private Node and(AndNode and) { int imm12; - return and.in(2) instanceof ConstantNode off && off._con instanceof SONTypeInteger ti && (imm12 = imm12Logical(ti)) != -1 + return and.in(2) instanceof ConstantNode off && off._con instanceof TypeInteger ti && (imm12 = imm12Logical(ti)) != -1 ? new AndIARM(and, imm12) : new AndARM(and); } private Node asr(SarNode asr) { - return asr.in(2) instanceof ConstantNode off && off._con instanceof SONTypeInteger ti && ti.value() >= 0 && ti.value() < 63 + return asr.in(2) instanceof ConstantNode off && off._con instanceof TypeInteger ti && ti.value() >= 0 && ti.value() < 63 ? new AsrIARM(asr, (int)ti.value()) : new AsrARM(asr); } private Node lsl(ShlNode lsl) { - return lsl.in(2) instanceof ConstantNode off && off._con instanceof SONTypeInteger ti && ti.value() >= 0 && ti.value() < 63 + return lsl.in(2) instanceof ConstantNode off && off._con instanceof TypeInteger ti && ti.value() >= 0 && ti.value() < 63 ? new LslIARM(lsl, (int)ti.value()) : new LslARM(lsl); } private Node lsr(ShrNode lsr) { - return lsr.in(2) instanceof ConstantNode off && off._con instanceof SONTypeInteger ti && ti.value() >= 0 && ti.value() < 63 + return lsr.in(2) instanceof ConstantNode off && off._con instanceof TypeInteger ti && ti.value() >= 0 && ti.value() < 63 ? new LsrIARM(lsr, (int)ti.value()) : new LsrARM(lsr); } @@ -800,8 +802,8 @@ private N address(N mop ) { Node base = mop.ptr(); // Skip/throw-away a ReadOnly, only used to typecheck if( base instanceof ReadOnlyNode read ) base = read.in(1); - assert !(base instanceof AddNode) && base._type instanceof SONTypeMemPtr; // Base ptr always, not some derived - if( mop.off() instanceof ConstantNode con && con._con instanceof SONTypeInteger ti && imm9(ti) ) { + assert !(base instanceof AddNode) && base._type instanceof TypeMemPtr; // Base ptr always, not some derived + if( mop.off() instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm9(ti) ) { off = (int)ti.value(); assert off == ti.value(); // In 32-bit range } else { diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/AUIPC.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/AUIPC.java index 8691f78..6dd5f28 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/AUIPC.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/AUIPC.java @@ -4,11 +4,11 @@ import com.compilerprogramming.ezlang.compiler.codegen.*; import com.compilerprogramming.ezlang.compiler.nodes.ConstantNode; import com.compilerprogramming.ezlang.compiler.nodes.MachNode; -import com.compilerprogramming.ezlang.compiler.sontypes.SONType; +import com.compilerprogramming.ezlang.compiler.sontypes.Type; // Add upper 20bits to PC. Immediate comes from the relocation info. public class AUIPC extends ConstantNode implements MachNode, RIPRelSize { - AUIPC( SONType tfp ) { super(tfp); } + AUIPC( Type tfp ) { super(tfp); } @Override public RegMask regmap(int i) { return null; } @Override public RegMask outregmap() { return riscv.WMASK; } @Override public boolean isClone() { return true; } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/CallEndRISC.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/CallEndRISC.java deleted file mode 100644 index 12f2b81..0000000 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/CallEndRISC.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.compilerprogramming.ezlang.compiler.nodes.cpus.riscv; - -import com.compilerprogramming.ezlang.compiler.nodes.CallEndNode; -import com.compilerprogramming.ezlang.compiler.nodes.MachNode; - -public class CallEndRISC extends CallEndNode implements MachNode { - CallEndRISC( CallEndNode cend ) { super(cend); } -} diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/CallRISC.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/CallRISC.java index 457ca77..79ab6ca 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/CallRISC.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/CallRISC.java @@ -3,33 +3,36 @@ import com.compilerprogramming.ezlang.compiler.*; import com.compilerprogramming.ezlang.compiler.codegen.*; import com.compilerprogramming.ezlang.compiler.nodes.*; -import com.compilerprogramming.ezlang.compiler.sontypes.SONTypeFunPtr; +import com.compilerprogramming.ezlang.compiler.sontypes.TypeFunPtr; public class CallRISC extends CallNode implements MachNode, RIPRelSize { - final SONTypeFunPtr _tfp; + final TypeFunPtr _tfp; final String _name; - CallRISC( CallNode call, SONTypeFunPtr tfp ) { + CallRISC( CallNode call, TypeFunPtr tfp ) { super(call); assert tfp.isConstant(); _inputs.pop(); // Pop constant target _tfp = tfp; - _name = CodeGen.CODE.link(tfp)._name; + FunNode fun = CodeGen.CODE.link(tfp); + _name = fun==null ? ((ExternNode)call.fptr())._extern : fun._name; // Can be null for extern calls } @Override public String op() { return "call"; } @Override public String label() { return op(); } - @Override public RegMask regmap(int i) { - return riscv.callInMask(_tfp,i,fun()._maxArgSlot); - } - @Override public RegMask outregmap() { return null; } @Override public String name() { return _name; } - @Override public SONTypeFunPtr tfp() { return _tfp; } + @Override public TypeFunPtr tfp() { return _tfp; } + @Override public RegMask regmap(int i) { return riscv.callInMask(_tfp,i,fun()._maxArgSlot); } + @Override public RegMask outregmap() { return riscv.RPC_MASK; } + @Override public int nargs() { return nIns()-2; } // Minus control, memory, fptr @Override public void encoding( Encoding enc ) { // Short form +/-4K: beq r0,r0,imm12 // Long form: auipc rX,imm20/32; jal r0,[rX+imm12/32] - enc.relo(this); - enc.add4(riscv.j_type(riscv.OP_JAL, riscv.RPC, 0)); + FunNode fun = CodeGen.CODE.link(_tfp); + if( fun==null ) enc.external(this,_name); + else enc.relo(this); + short rpc = enc.reg(this); + enc.add4(riscv.j_type(riscv.OP_JAL, rpc, 0)); } // Delta is from opcode start @@ -41,8 +44,9 @@ public class CallRISC extends CallNode implements MachNode, RIPRelSize { // Delta is from opcode start @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { + short rpc = enc.reg(this); if( opLen==4 ) { - enc.patch4(opStart,riscv.j_type(riscv.OP_JAL, riscv.RPC, delta)); + enc.patch4(opStart,riscv.j_type(riscv.OP_JAL, rpc, delta)); } else { throw Utils.TODO(); } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/FltRISC.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/FltRISC.java index f9dd6e6..4e8ab87 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/FltRISC.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/FltRISC.java @@ -1,11 +1,9 @@ package com.compilerprogramming.ezlang.compiler.nodes.cpus.riscv; import com.compilerprogramming.ezlang.compiler.SB; -import com.compilerprogramming.ezlang.compiler.Utils; import com.compilerprogramming.ezlang.compiler.codegen.*; import com.compilerprogramming.ezlang.compiler.nodes.ConstantNode; import com.compilerprogramming.ezlang.compiler.nodes.MachNode; -import com.compilerprogramming.ezlang.compiler.sontypes.SONTypeFloat; public class FltRISC extends ConstantNode implements MachNode, RIPRelSize { FltRISC(ConstantNode con) { super(con); } @@ -16,7 +14,7 @@ public class FltRISC extends ConstantNode implements MachNode, RIPRelSize { @Override public FltRISC copy() { return new FltRISC(this); } @Override public void encoding( Encoding enc ) { - enc.largeConstant(this,_con, 0, -1/*TODO: RISC5 style patching*/); + enc.largeConstant(this,_con, 0, -1); short dst = (short)(enc.reg(this) - riscv.F_OFFSET); short tmp = (short)riscv.T6; // AUIPC dst,#hi20_constant_pool @@ -27,7 +25,6 @@ public class FltRISC extends ConstantNode implements MachNode, RIPRelSize { @Override public RegMask killmap() { return new RegMask(riscv.T6); } // Delta is from opcode start. - // TODO: always size 8? @Override public byte encSize(int delta) { return 8; } // Delta is from opcode start diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/ImmRISC.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/ImmRISC.java index 150a8b9..59f638c 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/ImmRISC.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/ImmRISC.java @@ -3,7 +3,7 @@ import com.compilerprogramming.ezlang.compiler.*; import com.compilerprogramming.ezlang.compiler.codegen.*; import com.compilerprogramming.ezlang.compiler.nodes.*; -import com.compilerprogramming.ezlang.compiler.sontypes.SONTypeInteger; +import com.compilerprogramming.ezlang.compiler.sontypes.TypeInteger; import java.util.BitSet; abstract public class ImmRISC extends MachConcreteNode implements MachNode { @@ -40,8 +40,7 @@ abstract public class ImmRISC extends MachConcreteNode implements MachNode { @Override public void encoding( Encoding enc ) { short dst = enc.reg(this ); short src = enc.reg(in(1)); - int body = riscv.i_type(opcode(), dst, func3(), src, _imm12 & 0xFFF); - enc.add4(body); + enc.add4(riscv.i_type(opcode(), dst, func3(), src, _imm12 & 0xFFF)); } // General form: "addi rd = rs1 + imm" @@ -49,6 +48,6 @@ abstract public class ImmRISC extends MachConcreteNode implements MachNode { int imm12 = (_imm12<<20)>>20; // Sign extend 12 bits sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" ").p(glabel()).p(" #").p(imm12); if( in(1) instanceof LUI lui ) - sb.p(" // #").hex4((int)(((SONTypeInteger)lui._con).value()) + imm12); + sb.p(" // #").hex4((int)(((TypeInteger)lui._con).value()) + imm12); } } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/Int8RISC.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/Int8RISC.java new file mode 100644 index 0000000..9b56665 --- /dev/null +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/Int8RISC.java @@ -0,0 +1,47 @@ +package com.compilerprogramming.ezlang.compiler.nodes.cpus.riscv; + +import com.compilerprogramming.ezlang.compiler.nodes.ConstantNode; + +import com.compilerprogramming.ezlang.compiler.*; +import com.compilerprogramming.ezlang.compiler.codegen.*; +import com.compilerprogramming.ezlang.compiler.nodes.MachNode; + +// Special instruction for loading 8 byte constants from the constant pool. + +public class Int8RISC extends ConstantNode implements MachNode, RIPRelSize { + public Int8RISC(ConstantNode con) { super(con); } + + @Override public String op() { return "ld8"; } + @Override public RegMask regmap(int i) { return null; } + @Override public RegMask outregmap() { return riscv.WMASK; } + @Override public boolean isClone() { return true; } + @Override public Int8RISC copy() { return new Int8RISC(this); } + + @Override public byte encSize(int delta) { return 8; } + + @Override public void encoding( Encoding enc ) { + short dst = enc.reg(this); + short tmp = (short)riscv.T6; + enc.largeConstant(this,_con, 0, -1); + // AUIPC dst,#hi20_constant_pool + enc.add4(riscv.u_type(riscv.OP_AUIPC, tmp, 0)); + // Load dst,[dst+#low12_constant_pool] + enc.add4(riscv.i_type(riscv.OP_LOAD, dst, 0b11, tmp, 0)); + } + @Override public RegMask killmap() { return new RegMask(riscv.T6); } + + // Delta is from opcode start + @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { + short dst = enc.reg(this); + short tmp = (short)riscv.T6; + // AUIPC dst,#hi20_constant_pool + enc.patch4(opStart , riscv.u_type(riscv.OP_AUIPC, tmp, delta>>12)); + // Load dst,[dst+#low12_constant_pool] + enc.patch4(opStart+4, riscv.i_type(riscv.OP_LOAD, dst, 0b11, tmp, delta & 0xFFF)); + } + + @Override public void asm(CodeGen code, SB sb) { + _con.print(sb.p(code.reg(this)).p(" = #")); + } + +} diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/IntRISC.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/IntRISC.java index d01a11d..5b42b74 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/IntRISC.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/IntRISC.java @@ -4,8 +4,8 @@ import com.compilerprogramming.ezlang.compiler.codegen.*; import com.compilerprogramming.ezlang.compiler.nodes.ConstantNode; import com.compilerprogramming.ezlang.compiler.nodes.MachNode; -import com.compilerprogramming.ezlang.compiler.sontypes.SONType; -import com.compilerprogramming.ezlang.compiler.sontypes.SONTypeInteger; +import com.compilerprogramming.ezlang.compiler.sontypes.Type; +import com.compilerprogramming.ezlang.compiler.sontypes.TypeInteger; // 12-bit integer constant. Larger constants are made up in the instruction // selection by adding with a LUI. @@ -18,7 +18,7 @@ public class IntRISC extends ConstantNode implements MachNode { @Override public IntRISC copy() { return new IntRISC(this); } @Override public void encoding( Encoding enc ) { short dst = enc.reg(this); - int val = _con==SONType.NIL ? 0 : (int)(((SONTypeInteger)_con).value() & 0xFFF); + int val = _con==Type.NIL ? 0 : (int)(((TypeInteger)_con).value() & 0xFFF); // Explicit truncation of larger immediates; this will sign-extend on // load and this is handled during instruction selection. enc.add4(riscv.i_type(riscv.OP_IMM, dst, 0, riscv.ZERO, val)); diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/LUI.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/LUI.java index e63e001..435482e 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/LUI.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/LUI.java @@ -4,21 +4,21 @@ import com.compilerprogramming.ezlang.compiler.codegen.*; import com.compilerprogramming.ezlang.compiler.nodes.ConstantNode; import com.compilerprogramming.ezlang.compiler.nodes.MachNode; -import com.compilerprogramming.ezlang.compiler.sontypes.SONTypeInteger; +import com.compilerprogramming.ezlang.compiler.sontypes.TypeInteger; // Load upper 20bits. public class LUI extends ConstantNode implements MachNode { public LUI( int imm20 ) { - super(SONTypeInteger.constant(imm20)); - assert riscv.imm20Exact((SONTypeInteger)_con); + super(TypeInteger.constant(imm20)); + assert (imm20 & 0xFFF)==0; } @Override public RegMask regmap(int i) { return null; } @Override public RegMask outregmap() { return riscv.WMASK; } @Override public boolean isClone() { return true; } - @Override public LUI copy() { return new LUI((int)((SONTypeInteger)_con).value()); } + @Override public LUI copy() { return new LUI((int)((TypeInteger)_con).value()); } @Override public String op() { return "lui"; } @Override public void encoding( Encoding enc ) { - long x = ((SONTypeInteger)_con).value(); + long x = ((TypeInteger)_con).value(); int imm20 = (int)(x>>12) & 0xFFFFF; short dst = enc.reg(this); int lui = riscv.u_type(riscv.OP_LUI, dst, imm20); @@ -27,6 +27,6 @@ public LUI( int imm20 ) { @Override public void asm(CodeGen code, SB sb) { String reg = code.reg(this); - sb.p(reg).p(" = #").hex4((int)(((SONTypeInteger)_con).value())); + sb.p(reg).p(" = #").hex4((int)(((TypeInteger)_con).value())); } } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/MemOpRISC.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/MemOpRISC.java index 90b6a49..a74ef63 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/MemOpRISC.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/MemOpRISC.java @@ -12,7 +12,7 @@ public abstract class MemOpRISC extends MemOpNode implements MachNode { final char _sz; MemOpRISC(MemOpNode mop, Node base, int off, Node val) { super(mop,mop); - assert base._type instanceof SONTypeMemPtr; + assert base._type instanceof TypeMemPtr; _inputs.setX(2, base ); // Base can be an Add, is no longer raw object base _inputs.setX(3, null); // Never an index _inputs.setX(4, val ); @@ -25,7 +25,7 @@ public abstract class MemOpRISC extends MemOpNode implements MachNode { @Override public StringBuilder _printMach(StringBuilder sb, BitSet visited) { return sb.append(".").append(_name); } - @Override public SONType compute() { throw Utils.TODO(); } + @Override public Type compute() { throw Utils.TODO(); } @Override public Node idealize() { throw Utils.TODO(); } // func3 is based on load/store size and extend @@ -33,26 +33,28 @@ int func3() { int func3 = -1; // no unsigned flavour for store, so both signed and unsigned trigger the same if(this instanceof StoreRISC) { - if( _declaredType == SONTypeInteger. I8 || _declaredType == SONTypeInteger.U8 || _declaredType == SONTypeInteger.BOOL) func3=0; // SB - if( _declaredType == SONTypeInteger.I16 || _declaredType == SONTypeInteger.U16 ) func3=1; // SH - if( _declaredType == SONTypeInteger.I32 || _declaredType == SONTypeInteger.U32 || _declaredType instanceof SONTypeMemPtr) func3=2; // SW - if( _declaredType == SONTypeInteger.BOT ) func3=3; // SD + if( _declaredType == TypeInteger. I8 || _declaredType == TypeInteger.U8 || _declaredType == TypeInteger.BOOL) func3=0; // SB + if( _declaredType == TypeInteger.I16 || _declaredType == TypeInteger.U16 ) func3=1; // SH + if( _declaredType == TypeInteger.I32 || _declaredType == TypeInteger.U32 ) func3=2; // SW + if( _declaredType instanceof TypeMemPtr) func3=3; // SD + if( _declaredType == TypeInteger.BOT ) func3=3; // SD if( func3 == -1 ) throw Utils.TODO(); return func3; } - if( _declaredType == SONTypeInteger. I8 ) func3=0; // LB - if( _declaredType == SONTypeInteger.I16 ) func3=1; // LH - if( _declaredType == SONTypeInteger.I32 ) func3=2; // LW - if( _declaredType == SONTypeInteger.BOT ) func3=3; // LD - if( _declaredType == SONTypeInteger. U8 ) func3=4; // LBU - if( _declaredType == SONTypeInteger.BOOL) func3=4; // LBU - if( _declaredType == SONTypeInteger.U16 ) func3=5; // LHU - if( _declaredType == SONTypeInteger.U32 ) func3=6; // LWU + if( _declaredType == TypeInteger. I8 ) func3=0; // LB + if( _declaredType == TypeInteger.I16 ) func3=1; // LH + if( _declaredType == TypeInteger.I32 ) func3=2; // LW + if( _declaredType == TypeInteger.BOT ) func3=3; // LD + if( _declaredType == TypeInteger. U8 ) func3=4; // LBU + if( _declaredType == TypeInteger.BOOL) func3=4; // LBU + if( _declaredType == TypeInteger.U16 ) func3=5; // LHU + if( _declaredType == TypeInteger.U32 ) func3=6; // LWU // float - if(_declaredType == SONTypeFloat.F32) func3 = 2; // fLW fSW - if(_declaredType == SONTypeFloat.F64) func3 = 3; // fLD fSD - if( _declaredType instanceof SONTypeMemPtr ) func3=3; // 8 byte pointers + if( _declaredType == TypeFloat.F32) func3 = 2; // fLW fSW + if( _declaredType == TypeFloat.F64) func3 = 3; // fLD fSD + + if( _declaredType instanceof TypeMemPtr) func3 = 3; // 8 byte pointers (pick ld) if( func3 == -1 ) throw Utils.TODO(); return func3; } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/SraIRISC.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/SraIRISC.java index 2ccf60a..b8842ff 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/SraIRISC.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/SraIRISC.java @@ -4,7 +4,9 @@ import com.compilerprogramming.ezlang.compiler.nodes.Node; public class SraIRISC extends ImmRISC { - public SraIRISC( Node and, int imm) { super(and,imm); } + public SraIRISC( Node and, int imm) { + super(and,imm | (0x20 << 5)); + } @Override int opcode() { return riscv.OP_IMM; } @Override int func3() { return 5;} @Override public String glabel() { return ">>"; } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/TFPRISC.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/TFPRISC.java index d04275d..599fbed 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/TFPRISC.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/TFPRISC.java @@ -4,7 +4,8 @@ import com.compilerprogramming.ezlang.compiler.codegen.*; import com.compilerprogramming.ezlang.compiler.nodes.ConstantNode; import com.compilerprogramming.ezlang.compiler.nodes.MachNode; -import com.compilerprogramming.ezlang.compiler.sontypes.SONTypeFunPtr; +import com.compilerprogramming.ezlang.compiler.nodes.Node; +import com.compilerprogramming.ezlang.compiler.sontypes.TypeFunPtr; public class TFPRISC extends ConstantNode implements MachNode, RIPRelSize { TFPRISC(ConstantNode con) { super(con); } @@ -17,13 +18,11 @@ public class TFPRISC extends ConstantNode implements MachNode, RIPRelSize { enc.relo(this); // TODO: 1 op encoding, plus a TODO if it does not fit short dst = enc.reg(this); - SONTypeFunPtr tfp = (SONTypeFunPtr)_con; + TypeFunPtr tfp = (TypeFunPtr)_con; // auipc t0,0 - int auipc = riscv.u_type(riscv.OP_AUIPC, dst, 0); + enc.add4(riscv.u_type(riscv.OP_AUIPC, dst, 0)); // addi t1,t0 + #0 - int addi = riscv.i_type(riscv.OP_IMM, dst, 0, dst, 0); - enc.add4(auipc); - enc.add4(addi); + enc.add4(riscv.i_type(riscv.OP_IMM, dst, 0, dst, 0)); } @Override public byte encSize(int delta) { @@ -38,7 +37,7 @@ public class TFPRISC extends ConstantNode implements MachNode, RIPRelSize { // AUIPC (upper 20 bits) // opstart of add int next = opStart + opLen; - enc.patch4(opStart,riscv.u_type(riscv.OP_AUIPC, rpc, delta)); + enc.patch4(opStart,riscv.u_type(riscv.OP_AUIPC, rpc, delta>>12)); // addi(low 12 bits) enc.patch4(next,riscv.i_type(riscv.OP_IMM, rpc, 0, rpc, delta & 0xFFF)); // addi @@ -51,5 +50,5 @@ public class TFPRISC extends ConstantNode implements MachNode, RIPRelSize { @Override public void asm(CodeGen code, SB sb) { _con.print(sb.p(code.reg(this)).p(" #")); } - + @Override public boolean eq(Node n) { return this==n; } } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/TMPRISC.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/TMPRISC.java new file mode 100644 index 0000000..6079e6c --- /dev/null +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/TMPRISC.java @@ -0,0 +1,41 @@ +package com.compilerprogramming.ezlang.compiler.nodes.cpus.riscv; + +import com.compilerprogramming.ezlang.compiler.*; +import com.compilerprogramming.ezlang.compiler.codegen.*; +import com.compilerprogramming.ezlang.compiler.nodes.ConstantNode; +import com.compilerprogramming.ezlang.compiler.nodes.MachNode; +import com.compilerprogramming.ezlang.compiler.nodes.Node; +import com.compilerprogramming.ezlang.compiler.sontypes.TypeMemPtr; + +public class TMPRISC extends ConstantNode implements MachNode, RIPRelSize { + TMPRISC(ConstantNode con) { super(con); } + @Override public String op() { return "ldp"; } + @Override public RegMask regmap(int i) { return null; } + @Override public RegMask outregmap() { return riscv.WMASK; } + @Override public boolean isClone() { return true; } + @Override public TMPRISC copy() { return new TMPRISC(this); } + @Override public void encoding( Encoding enc ) { + enc.largeConstant(this,((TypeMemPtr)_con)._obj,0,-1); + short dst = enc.reg(this); + // AUIPC dst,#hi20_constant_pool + enc.add4(riscv.u_type(riscv.OP_AUIPC, dst, 0)); + // addi dst,[dst+#low12_constant_pool] + enc.add4(riscv.i_type(riscv.OP_IMM, dst, 0, dst, 0)); + } + + @Override public byte encSize(int delta) { return 8; } + + // Delta is from opcode start + @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { + short dst = enc.reg(this); + // AUIPC dst,#hi20_constant_pool + enc.patch4(opStart , riscv.u_type(riscv.OP_AUIPC, dst, delta>>12)); + // Load dst,[dst+#low12_constant_pool] + enc.patch4(opStart+4, riscv.i_type(riscv.OP_IMM, dst, 0, dst, delta & 0xFFF)); + } + + @Override public void asm(CodeGen code, SB sb) { + _con.print(sb.p(code.reg(this)).p(" #")); + } + @Override public boolean eq(Node n) { return this==n; } +} diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/UJmpRISC.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/UJmpRISC.java index 7ddb3aa..f85809f 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/UJmpRISC.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/UJmpRISC.java @@ -3,7 +3,7 @@ import com.compilerprogramming.ezlang.compiler.*; import com.compilerprogramming.ezlang.compiler.codegen.*; import com.compilerprogramming.ezlang.compiler.nodes.*; -import com.compilerprogramming.ezlang.compiler.sontypes.SONType; +import com.compilerprogramming.ezlang.compiler.sontypes.Type; import java.util.BitSet; // unconditional jump @@ -13,7 +13,7 @@ public class UJmpRISC extends CFGNode implements MachNode, RIPRelSize { @Override public StringBuilder _print1( StringBuilder sb, BitSet visited ) { return sb.append("jmp "); } @Override public RegMask regmap(int i) {return null; } @Override public RegMask outregmap() { return null; } - @Override public SONType compute() { throw Utils.TODO(); } + @Override public Type compute() { throw Utils.TODO(); } @Override public Node idealize() { throw Utils.TODO(); } @Override public void encoding( Encoding enc ) { // Short form +/-4K: beq r0,r0,imm12 diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/XorIRISC.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/XorIRISC.java index b7c03b0..9672291 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/XorIRISC.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/XorIRISC.java @@ -5,6 +5,7 @@ public class XorIRISC extends ImmRISC { public XorIRISC( Node and, int imm) { super(and,imm); } + public XorIRISC( Node and, int imm, boolean pop) { super(and,imm,pop); } @Override int opcode() { return riscv.OP_IMM; } @Override int func3() { return 4; } @Override public String glabel() { return "^"; } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/riscv.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/riscv.java index b051fef..6018b9d 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/riscv.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/riscv.java @@ -188,7 +188,6 @@ public static int i_type(int opcode, int rd, int func3, int rs1, int imm12) { return (imm12 << 20) | (rs1 << 15) | (func3 << 12) | (rd << 7) | opcode; } - // S-type instructions(store) public static int s_type(int opcode, int func3, int rs1, int rs2, int imm12) { assert 0 <= rs1 && rs1 < 32; @@ -253,17 +252,18 @@ static public int fsetop(String op) { }; } - @Override public RegMask callArgMask( SONTypeFunPtr tfp, int idx, int maxArgSlot ) { return callInMask(tfp,idx,maxArgSlot); } - static RegMask callInMask( SONTypeFunPtr tfp, int idx, int maxArgSlot ) { + @Override public RegMask callArgMask( TypeFunPtr tfp, int idx, int maxArgSlot ) { return callInMask(tfp,idx,maxArgSlot); } + static RegMask callInMask( TypeFunPtr tfp, int idx, int maxArgSlot ) { if( idx==0 ) return RPC_MASK; if( idx==1 ) return null; + if( idx-2 >= tfp.nargs() ) return null; // Anti-dependence // Count floats in signature up to index int fcnt=0; for( int i=2; i>52) == ti.value(); } // True if HIGH 20-bit signed immediate, with all zeros low. - public static boolean imm20Exact(SONTypeInteger ti) { + public static boolean imm20Exact(TypeInteger ti) { // shift left 32 to clear out the upper 32 bits. // shift right SIGNED to sign-extend upper 32 bits; then shift 12 more to clear out lower 12 bits. // shift left 12 to re-center the bits. - return ti.isConstant() && (((ti.value()<<32)>>>44)<<12) == ti.value(); + return ti.isConstant() && (((ti.value()<<32)>>44)<<12) == ti.value(); } @Override public Node instSelect( Node n ) { @@ -328,8 +328,8 @@ public static boolean imm20Exact(SONTypeInteger ti) { case AndNode and -> and(and); case BoolNode bool -> cmp(bool); case CallNode call -> call(call); - case CastNode cast -> new CastRISC(cast); - case CallEndNode cend -> new CallEndRISC(cend); + case CastNode cast -> new CastMach(cast); + case CallEndNode cend -> new CallEndMach(cend); case CProjNode c -> new CProjNode(c); case ConstantNode con -> con(con); case DivFNode divf -> new DivFRISC(divf); @@ -347,7 +347,7 @@ public static boolean imm20Exact(SONTypeInteger ti) { case ParmNode parm -> new ParmRISC(parm); case PhiNode phi -> new PhiNode(phi); case ProjNode prj -> prj(prj); - case ReadOnlyNode read-> new ReadOnlyNode(read); + case ReadOnlyNode read-> new ReadOnlyMach(read); case ReturnNode ret -> new RetRISC(ret, ret.fun()); case SarNode sar -> sra(sar); case ShlNode shl -> sll(shl); @@ -371,13 +371,13 @@ private Node addf(AddFNode addf) { } private Node add(AddNode add) { - if( add.in(2) instanceof ConstantNode off2 && off2._con instanceof SONTypeInteger ti && imm12(ti) ) + if( add.in(2) instanceof ConstantNode off2 && off2._con instanceof TypeInteger ti && imm12(ti) ) return new AddIRISC(add, (int)ti.value(),true); return new AddRISC(add); } private Node and(AndNode and) { - if( and.in(2) instanceof ConstantNode con && con._con instanceof SONTypeInteger ti ) { + if( and.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti ) { if( imm12(ti) ) return new AndIRISC(and, (int)ti.value()); // Could be any size low bit mask @@ -388,7 +388,7 @@ private Node and(AndNode and) { } private Node call(CallNode call) { - return call.fptr() instanceof ConstantNode con && con._con instanceof SONTypeFunPtr tfp + return call.fptr() instanceof ConstantNode con && con._con instanceof TypeFunPtr tfp ? new CallRISC(call, tfp) : new CallRRISC(call); } @@ -416,11 +416,11 @@ private Node cmp(BoolNode bool) { // we can remove the double XOR in the encodings. return switch( bool.op() ) { - case "<" -> bool.in(2) instanceof ConstantNode con && con._con instanceof SONTypeInteger ti && imm12(ti) + case "<" -> bool.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm12(ti) ? new SetIRISC(bool, (int)ti.value(),false) : new SetRISC(bool, false); // x <= y - flip and negate; !(y < x); `slt tmp=y,x; xori dst=tmp,#1` - case "<=" -> new XorIRISC(new SetRISC(bool.swap12(), false),1); + case "<=" -> new XorIRISC(new SetRISC(bool.swap12(), false),1,false); // x == y - sub and vs0 == `sub tmp=x-y; sltu dst=tmp,#1` case "==" -> new SetIRISC(new SubRISC(bool),1,true); default -> throw Utils.TODO(); @@ -430,7 +430,7 @@ private Node cmp(BoolNode bool) { private Node con( ConstantNode con ) { if( !con._con.isConstant() ) return new ConstantNode( con ); // Default unknown caller inputs return switch( con._con ) { - case SONTypeInteger ti -> { + case TypeInteger ti -> { if( imm12(ti) ) yield new IntRISC(con); long x = ti.value(); if( imm20Exact(ti) ) yield new LUI((int)x); @@ -443,15 +443,15 @@ private Node con( ConstantNode con ) { } // Need more complex sequence for larger constants... or a load // from a constant pool, which does not need an extra register - throw Utils.TODO(); + yield new Int8RISC(con); } // Load from constant pool - case SONTypeFloat tf -> new FltRISC(con); - case SONTypeFunPtr tfp -> new TFPRISC(con); - case SONTypeMemPtr tmp -> throw Utils.TODO(); - case SONTypeNil tn -> throw Utils.TODO(); + case TypeFloat tf -> new FltRISC(con); + case TypeFunPtr tfp -> new TFPRISC(con); + case TypeMemPtr tmp -> new TMPRISC(con); + case TypeNil tn -> throw Utils.TODO(); // TOP, BOTTOM, XCtrl, Ctrl, etc. Never any executable code. - case SONType t -> t==SONType.NIL ? new IntRISC(con) : new ConstantNode(con); + case Type t -> t==Type.NIL ? new IntRISC(con) : new ConstantNode(con); }; } @@ -468,43 +468,43 @@ private Node jmp( IfNode iff ) { } private Node or(OrNode or) { - if( or.in(2) instanceof ConstantNode con && con._con instanceof SONTypeInteger ti && imm12(ti)) + if( or.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm12(ti)) return new OrIRISC(or, (int)ti.value()); return new OrRISC(or); } private Node xor(XorNode xor) { - if( xor.in(2) instanceof ConstantNode con && con._con instanceof SONTypeInteger ti && imm12(ti)) + if( xor.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm12(ti)) return new XorIRISC(xor, (int)ti.value()); return new XorRISC(xor); } private Node sra(SarNode sar) { - if( sar.in(2) instanceof ConstantNode con && con._con instanceof SONTypeInteger ti && imm12(ti)) + if( sar.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm12(ti)) return new SraIRISC(sar, (int)ti.value()); return new SraRISC(sar); } private Node srl(ShrNode shr) { - if( shr.in(2) instanceof ConstantNode con && con._con instanceof SONTypeInteger ti && imm12(ti)) + if( shr.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm12(ti)) return new SrlIRISC(shr, (int)ti.value(),true); return new SrlRISC(shr); } private Node sll(ShlNode sll) { - if( sll.in(2) instanceof ConstantNode con && con._con instanceof SONTypeInteger ti && imm12(ti)) + if( sll.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm12(ti)) return new SllIRISC(sll, (int)ti.value()); return new SllRISC(sll); } private Node sub(SubNode sub) { - return sub.in(2) instanceof ConstantNode con && con._con instanceof SONTypeInteger ti && imm12(ti) + return sub.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm12(ti) ? new AddIRISC(sub, (int)(-ti.value()),true) : new SubRISC(sub); } private Node i2f8(ToFloatNode tfn) { - assert tfn.in(1)._type instanceof SONTypeInteger ti; + assert tfn.in(1)._type instanceof TypeInteger ti; return new I2F8RISC(tfn); } @@ -517,7 +517,7 @@ private Node ld(LoadNode ld) { } private Node st(StoreNode st) { - Node xval = st.val() instanceof ConstantNode con && con._con == SONTypeInteger.ZERO ? null : st.val(); + Node xval = st.val() instanceof ConstantNode con && con._con == TypeInteger.ZERO ? null : st.val(); return new StoreRISC(st,address(st), off, xval); } @@ -530,8 +530,8 @@ private Node address( MemOpNode mop ) { Node base = mop.ptr(); // Skip/throw-away a ReadOnly, only used to typecheck if( base instanceof ReadOnlyNode read ) base = read.in(1); - assert !(base instanceof AddNode) && base._type instanceof SONTypeMemPtr; // Base ptr always, not some derived - if( mop.off() instanceof ConstantNode con && con._con instanceof SONTypeInteger ti && imm12(ti) ) { + assert !(base instanceof AddNode) && base._type instanceof TypeMemPtr; // Base ptr always, not some derived + if( mop.off() instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm12(ti) ) { off = (int)ti.value(); } else { base = new AddRISC(base,mop.off()); diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/AddIX86.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/AddIX86.java index 7659e35..b3f3f9f 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/AddIX86.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/AddIX86.java @@ -1,5 +1,6 @@ package com.compilerprogramming.ezlang.compiler.nodes.cpus.x86_64_v2; +import com.compilerprogramming.ezlang.compiler.codegen.Encoding; import com.compilerprogramming.ezlang.compiler.nodes.Node; public class AddIX86 extends ImmX86 { @@ -10,4 +11,12 @@ public class AddIX86 extends ImmX86 { @Override public String glabel() { return "+"; } @Override int opcode() { return 0x81; } @Override int mod() { return 0; } + @Override public final void encoding( Encoding enc ) { + if( _imm== 1 || _imm== -1 ) { + short dst = enc.reg(this); // Also src1 + enc.add1( x86_64_v2.rex(0,dst,0)); + enc.add1(0xFF); + enc.add1( x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, _imm==1 ? 0 : 1, dst) ); + } else super.encoding(enc); + } } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/CallEndX86.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/CallEndX86.java deleted file mode 100644 index 1dfff37..0000000 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/CallEndX86.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.compilerprogramming.ezlang.compiler.nodes.cpus.x86_64_v2; - -import com.compilerprogramming.ezlang.compiler.nodes.CallEndNode; -import com.compilerprogramming.ezlang.compiler.nodes.MachNode; - -public class CallEndX86 extends CallEndNode implements MachNode { - CallEndX86( CallEndNode cend ) { super(cend); } -} diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/CallX86.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/CallX86.java index ec9b60d..b43ea38 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/CallX86.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/CallX86.java @@ -3,29 +3,35 @@ import com.compilerprogramming.ezlang.compiler.SB; import com.compilerprogramming.ezlang.compiler.codegen.*; import com.compilerprogramming.ezlang.compiler.nodes.CallNode; +import com.compilerprogramming.ezlang.compiler.nodes.ExternNode; +import com.compilerprogramming.ezlang.compiler.nodes.FunNode; import com.compilerprogramming.ezlang.compiler.nodes.MachNode; -import com.compilerprogramming.ezlang.compiler.sontypes.SONTypeFunPtr; +import com.compilerprogramming.ezlang.compiler.sontypes.TypeFunPtr; public class CallX86 extends CallNode implements MachNode, RIPRelSize { - final SONTypeFunPtr _tfp; + final TypeFunPtr _tfp; final String _name; - CallX86( CallNode call, SONTypeFunPtr tfp ) { + CallX86( CallNode call, TypeFunPtr tfp ) { super(call); _inputs.pop(); // Pop constant target assert tfp.isConstant(); _tfp = tfp; - _name = CodeGen.CODE.link(tfp)._name; + FunNode fun = CodeGen.CODE.link(tfp); + _name = fun==null ? ((ExternNode)call.fptr())._extern : fun._name; // Can be null for extern calls } @Override public String op() { return "call"; } @Override public String label() { return op(); } @Override public String name() { return _name; } - @Override public SONTypeFunPtr tfp() { return _tfp; } + @Override public TypeFunPtr tfp() { return _tfp; } @Override public RegMask regmap(int i) { return x86_64_v2.callInMask(_tfp,i,fun()._maxArgSlot); } @Override public RegMask outregmap() { return null; } @Override public int nargs() { return nIns()-2; } // Minus control, memory, fptr @Override public void encoding( Encoding enc ) { - enc.relo(this).add1(0xe8).add4(0); + FunNode fun = CodeGen.CODE.link(_tfp); + if( fun==null ) enc.external(this,_name); + else enc.relo(this); + enc.add1(0xe8).add4(0); } // Delta is from opcode start, but X86 measures from the end of the 5-byte encoding diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/CastX86.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/CastX86.java deleted file mode 100644 index f494e79..0000000 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/CastX86.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.compilerprogramming.ezlang.compiler.nodes.cpus.x86_64_v2; - -import com.compilerprogramming.ezlang.compiler.SB; -import com.compilerprogramming.ezlang.compiler.codegen.*; -import com.compilerprogramming.ezlang.compiler.nodes.CastNode; -import com.compilerprogramming.ezlang.compiler.nodes.MachNode; - -public class CastX86 extends CastNode implements MachNode { - CastX86( CastNode cast ) { super(cast); } - @Override public String op() { return label(); } - @Override public RegMask regmap(int i) { assert i==1; return RegMask.FULL; } - @Override public RegMask outregmap() { return RegMask.FULL; } - @Override public int twoAddress( ) { return 1; } - @Override public void encoding( Encoding enc ) { } - @Override public void asm(CodeGen code, SB sb) { _t.print(sb.p(code.reg(in(1))).p(" isa ")); } -} diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/CmpMemX86.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/CmpMemX86.java index d2bd42a..308e0f5 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/CmpMemX86.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/CmpMemX86.java @@ -3,15 +3,15 @@ import com.compilerprogramming.ezlang.compiler.SB; import com.compilerprogramming.ezlang.compiler.codegen.*; import com.compilerprogramming.ezlang.compiler.nodes.*; -import com.compilerprogramming.ezlang.compiler.sontypes.SONType; -import com.compilerprogramming.ezlang.compiler.sontypes.SONTypeFloat; +import com.compilerprogramming.ezlang.compiler.sontypes.Type; +import com.compilerprogramming.ezlang.compiler.sontypes.TypeFloat; public class CmpMemX86 extends MemOpX86 { final boolean _swap; // Op switched LHS, RHS CmpMemX86( BoolNode bool, LoadNode ld, Node base, Node idx, int off, int scale, int imm, Node val, boolean swap ) { super(bool,ld, base, idx, off, scale, imm, val ); _swap = swap; - assert !_swap || val() == null || bool.op()=="==" || bool.op()=="!="; // Cannot swap with immediate + assert !_swap || val() != null || bool.op()=="==" || bool.op()=="!="; // Cannot swap with immediate } @Override public String op() { return ((val()==null && _imm==0) ? "test" : "cmp") + _sz; } @Override public RegMask outregmap() { return x86_64_v2.FLAGS_MASK; } @@ -45,10 +45,10 @@ public class CmpMemX86 extends MemOpX86 { } } - static void encVal(Encoding enc, SONType decl, short ptr, short idx, short src, int off, int scale, boolean _swap) { - if(decl instanceof SONTypeFloat) { + static void encVal(Encoding enc, Type decl, short ptr, short idx, short src, int off, int scale, boolean _swap) { + if(decl instanceof TypeFloat) { src -= (short)x86_64_v2.XMM_OFFSET; - enc.add1(decl==SONTypeFloat.F32 ? 0xF3 : 0xF2).add1(0x0F).add1(0xC2); + enc.add1(decl==TypeFloat.F32 ? 0xF3 : 0xF2).add1(0x0F).add1(0xC2); } else { int log = decl.log_size(); x86_64_v2.rexF(src, ptr, idx, log == 3, enc); diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/CmpX86.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/CmpX86.java index b238ed2..563cb9d 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/CmpX86.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/CmpX86.java @@ -9,6 +9,12 @@ public class CmpX86 extends MachConcreteNode implements MachNode { @Override public String op() { return "cmp"; } @Override public RegMask regmap(int i) { return x86_64_v2.RMASK; } @Override public RegMask outregmap() { return x86_64_v2.FLAGS_MASK; } + // This one is marginal: cloning a Cmp[reg,reg] means stretching the + // lifetimes of 2 normal registers in exchange for shortening a flags + // register lifetime. Spilling flags is (probably) relatively expensive + // compared to some normal registers - and those normal registers might not + // be spilling! + @Override public boolean isClone() { return true; } @Override public void encoding( Encoding enc ) { short dst = enc.reg(in(1)); diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/DivX86.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/DivX86.java index 301cb2c..83a5dda 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/DivX86.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/DivX86.java @@ -8,7 +8,7 @@ public class DivX86 extends MachConcreteNode implements MachNode { DivX86( Node div ) { super(div); } @Override public String op() { return "div"; } @Override public RegMask regmap(int i) { - return (i==1) ? x86_64_v2.RAX_MASK : x86_64_v2.RMASK; + return (i==1) ? x86_64_v2.RAX_MASK : x86_64_v2.DIV_MASK; } @Override public RegMask outregmap() { return x86_64_v2.RAX_MASK; } @Override public RegMask killmap() { return x86_64_v2.RDX_MASK; } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/ImmX86.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/ImmX86.java index f86e852..4b33b82 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/ImmX86.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/ImmX86.java @@ -3,7 +3,6 @@ import com.compilerprogramming.ezlang.compiler.*; import com.compilerprogramming.ezlang.compiler.codegen.*; import com.compilerprogramming.ezlang.compiler.nodes.*; -import com.compilerprogramming.ezlang.compiler.sontypes.SONTypeInteger; public abstract class ImmX86 extends MachConcreteNode implements MachNode { final int _imm; @@ -15,11 +14,12 @@ public abstract class ImmX86 extends MachConcreteNode implements MachNode { @Override public RegMask regmap(int i) { return x86_64_v2.RMASK; } @Override public RegMask outregmap() { return x86_64_v2.WMASK; } @Override public int twoAddress() { return 1; } + @Override public RegMask killmap() { return x86_64_v2.FLAGS_MASK; } abstract int opcode(); abstract int mod(); - @Override public final void encoding( Encoding enc ) { + @Override public void encoding( Encoding enc ) { short dst = enc.reg(this); // Also src1 enc.add1(x86_64_v2.rex(0, dst, 0)); // opcode; 0x81 or 0x83; 0x69 or 0x6B diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/IntX86.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/IntX86.java index 6067ac8..243d0e1 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/IntX86.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/IntX86.java @@ -3,14 +3,14 @@ import com.compilerprogramming.ezlang.compiler.*; import com.compilerprogramming.ezlang.compiler.codegen.*; import com.compilerprogramming.ezlang.compiler.nodes.*; -import com.compilerprogramming.ezlang.compiler.sontypes.SONType; -import com.compilerprogramming.ezlang.compiler.sontypes.SONTypeInteger; +import com.compilerprogramming.ezlang.compiler.sontypes.Type; +import com.compilerprogramming.ezlang.compiler.sontypes.TypeInteger; // Integer constants public class IntX86 extends ConstantNode implements MachNode { IntX86( ConstantNode con ) { super(con); } @Override public String op() { - return _con == SONType.NIL || _con == SONTypeInteger.ZERO ? "xor" : "ldi"; + return _con == Type.NIL || _con == TypeInteger.ZERO ? "xor" : "ldi"; } @Override public boolean isClone() { return true; } @Override public Node copy() { return new IntX86(this); } @@ -18,13 +18,13 @@ public class IntX86 extends ConstantNode implements MachNode { @Override public RegMask outregmap() { return x86_64_v2.WMASK; } // Zero-set uses XOR kills flags @Override public RegMask killmap() { - return _con == SONType.NIL || _con == SONTypeInteger.ZERO ? x86_64_v2.FLAGS_MASK : null; + return _con == Type.NIL || _con == TypeInteger.ZERO ? x86_64_v2.FLAGS_MASK : null; } @Override public void encoding( Encoding enc ) { short dst = enc.reg(this); // Short form for zero - if( _con==SONType.NIL || _con==SONTypeInteger.ZERO ) { + if( _con==Type.NIL || _con==TypeInteger.ZERO ) { // XOR dst,dst. Can skip REX is dst is low 8, makes this a 32b // xor, which will also zero the high bits. if( dst >= 8 ) enc.add1(x86_64_v2.rex(dst, dst, 0)); @@ -37,7 +37,7 @@ public class IntX86 extends ConstantNode implements MachNode { // Conditional encoding based on 64 or 32 bits //REX.W + C7 /0 id MOV r/m64, imm32 - long imm = ((SONTypeInteger)_con).value(); + long imm = ((TypeInteger)_con).value(); if (Integer.MIN_VALUE <= imm && imm < 0) { // We need sign extension, so use imm32 into 64 bit register // REX.W + C7 /0 id MOV r/m64, imm32 @@ -68,7 +68,7 @@ public class IntX86 extends ConstantNode implements MachNode { // General form: "op\tdst=src+src" @Override public void asm(CodeGen code, SB sb) { String reg = code.reg(this); - if( _con == SONType.NIL || _con == SONTypeInteger.ZERO ) + if( _con == Type.NIL || _con == TypeInteger.ZERO ) sb.p(reg).p(",").p(reg); else _con.print(sb.p(reg).p(" = #")); diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/LoadX86.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/LoadX86.java index c35e176..6b308c2 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/LoadX86.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/LoadX86.java @@ -5,10 +5,9 @@ import com.compilerprogramming.ezlang.compiler.codegen.*; import com.compilerprogramming.ezlang.compiler.nodes.LoadNode; import com.compilerprogramming.ezlang.compiler.nodes.Node; -import com.compilerprogramming.ezlang.compiler.sontypes.SONType; -import com.compilerprogramming.ezlang.compiler.sontypes.SONTypeFloat; -import com.compilerprogramming.ezlang.compiler.sontypes.SONTypeInteger; -import com.compilerprogramming.ezlang.compiler.sontypes.SONTypeMemPtr; +import com.compilerprogramming.ezlang.compiler.sontypes.Type; +import com.compilerprogramming.ezlang.compiler.sontypes.TypeFloat; +import com.compilerprogramming.ezlang.compiler.sontypes.TypeInteger; public class LoadX86 extends MemOpX86 { LoadX86( LoadNode ld, Node base, Node idx, int off, int scale ) { @@ -26,23 +25,23 @@ public class LoadX86 extends MemOpX86 { enc(enc, _declaredType, dst, ptr, idx, _off, _scale); } - static void enc( Encoding enc, SONType decl, short dst, short ptr, short idx, int off, int scale ) { - if( decl == SONTypeFloat.F32) enc.add1(0xF3); - if( decl == SONTypeFloat.F64) enc.add1(0xF2); + static void enc( Encoding enc, Type decl, short dst, short ptr, short idx, int off, int scale ) { + if( decl == TypeFloat.F32) enc.add1(0xF3); + if( decl == TypeFloat.F64) enc.add1(0xF2); - if( decl.isa(SONTypeFloat.F64) ) + if( decl.isa(TypeFloat.F64) ) dst -= (short)x86_64_v2.XMM_OFFSET; - x86_64_v2.rexF(dst, ptr, idx, decl != SONTypeInteger.U32 && decl != SONTypeFloat.F32 && decl != SONTypeFloat.F64, enc); + x86_64_v2.rexF(dst, ptr, idx, decl != TypeInteger.U32 && decl != TypeFloat.F32 && decl != TypeFloat.F64, enc); if( false ) ; - else if( decl == SONTypeFloat.F32 ) enc.add1(0x0F).add1(0x10); // F3 0F 10 /r MOVSS xmm1, m32 - else if( decl == SONTypeFloat.F64 ) enc.add1(0x0F).add1(0x10); // F2 0F 10 /r MOVSD xmm1, m64 - else if( decl.isa(SONTypeInteger.I8)) enc.add1(0x0F).add1(0xBE); // sign extend: REX.W + 0F BE /r MOVSX r64, r/m8 - else if( decl == SONTypeInteger.I16 ) enc.add1(0x0F).add1(0xBF); // sign extend: REX.W + 0F BF /r MOVSX r64, r/m16 - else if( decl == SONTypeInteger.I32 ) enc.add1(0x63); // sign extend: REX.W + 63 /r MOVSXD r64, r/m32 - else if( decl == SONTypeInteger.U8 ) enc.add1(0x0F).add1(0xB6); // zero extend: REX.W + 0F B6 /r MOVZX r64, r/m8 - else if( decl == SONTypeInteger.U16 ) enc.add1(0x0F).add1(0xB7); // zero extend: REX.W + 0F B7 /r MOVZX r64, r/m16 + else if( decl == TypeFloat.F32 ) enc.add1(0x0F).add1(0x10); // F3 0F 10 /r MOVSS xmm1, m32 + else if( decl == TypeFloat.F64 ) enc.add1(0x0F).add1(0x10); // F2 0F 10 /r MOVSD xmm1, m64 + else if( decl.isa(TypeInteger.I8)) enc.add1(0x0F).add1(0xBE); // sign extend: REX.W + 0F BE /r MOVSX r64, r/m8 + else if( decl == TypeInteger.I16 ) enc.add1(0x0F).add1(0xBF); // sign extend: REX.W + 0F BF /r MOVSX r64, r/m16 + else if( decl == TypeInteger.I32 ) enc.add1(0x63); // sign extend: REX.W + 63 /r MOVSXD r64, r/m32 + else if( decl == TypeInteger.U8 ) enc.add1(0x0F).add1(0xB6); // zero extend: REX.W + 0F B6 /r MOVZX r64, r/m8 + else if( decl == TypeInteger.U16 ) enc.add1(0x0F).add1(0xB7); // zero extend: REX.W + 0F B7 /r MOVZX r64, r/m16 // Covers U32, I64/BOT, TMP else if( decl.log_size()>=2 ) enc.add1(0x8B); // zero extend: 8B /r MOV r32, r/m32 else throw Utils.TODO(); diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/MemAddX86.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/MemAddX86.java index a0edf38..205ad36 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/MemAddX86.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/MemAddX86.java @@ -13,6 +13,7 @@ public class MemAddX86 extends MemOpX86 { } // Register mask allowed as a result. 0 for no register. @Override public RegMask outregmap() { return null; } + @Override public RegMask killmap() { return x86_64_v2.FLAGS_MASK; } @Override public void encoding( Encoding enc ) { // add something to memory // REX.W + 01 /r | REX.W + 81 /0 id @@ -23,11 +24,11 @@ public class MemAddX86 extends MemOpX86 { enc.add1(x86_64_v2.rex(src, ptr, idx)); // opcode - enc.add1( src == -1 ? 0x81: 0x01); + enc.add1( src == -1 ? (_imm==1 ? 0xFF : 0x81): 0x01); // includes modrm x86_64_v2.indirectAdr(_scale, idx, ptr, _off, src == -1 ? 0 : src, enc); - if( src == -1 ) enc.add4(_imm); + if( src == -1 && _imm!=1 ) enc.add4(_imm); } // General form: "add [base + idx<<2 + 12] += src" @Override public void asm(CodeGen code, SB sb) { diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/MemOpX86.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/MemOpX86.java index e6e064d..ca9e4aa 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/MemOpX86.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/MemOpX86.java @@ -26,7 +26,7 @@ public abstract class MemOpX86 extends MemOpNode implements MachNode { final char _sz; // Handy print name MemOpX86( Node op, MemOpNode mop, Node base, Node idx, int off, int scale, int imm ) { super(op,mop); - assert base._type instanceof SONTypeMemPtr && !(base instanceof AddNode); + assert base._type instanceof TypeMemPtr && !(base instanceof AddNode); assert (idx==null && scale==0) || (idx!=null && 0<= scale && scale<=3); // Copy memory parts from e.g. the LoadNode over the opcode, e.g. an Add @@ -58,7 +58,7 @@ public abstract class MemOpX86 extends MemOpNode implements MachNode { } @Override public String label() { return op(); } - @Override public SONType compute() { throw Utils.TODO(); } + @Override public Type compute() { throw Utils.TODO(); } @Override public Node idealize() { throw Utils.TODO(); } // Register mask allowed on input i. diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/MulIX86.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/MulIX86.java index c53599d..8f0a90c 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/MulIX86.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/MulIX86.java @@ -1,11 +1,38 @@ package com.compilerprogramming.ezlang.compiler.nodes.cpus.x86_64_v2; +import com.compilerprogramming.ezlang.compiler.SB; +import com.compilerprogramming.ezlang.compiler.codegen.CodeGen; +import com.compilerprogramming.ezlang.compiler.codegen.Encoding; +import com.compilerprogramming.ezlang.compiler.codegen.RegMask; +import com.compilerprogramming.ezlang.compiler.nodes.MachConcreteNode; +import com.compilerprogramming.ezlang.compiler.nodes.MachNode; import com.compilerprogramming.ezlang.compiler.nodes.Node; -public class MulIX86 extends ImmX86 { - MulIX86( Node add, int imm ) { super(add,imm); } +public class MulIX86 extends MachConcreteNode implements MachNode { + final int _imm; + MulIX86( Node add, int imm ) { + super(add); + _inputs.pop(); // Pop the constant input + _imm = imm; // Record the constant + } @Override public String op() { return "muli"; } @Override public String glabel() { return "*"; } - @Override int opcode() { return 0x69; } - @Override int mod() { return 0; } + @Override public RegMask regmap(int i) { return x86_64_v2.RMASK; } + @Override public RegMask outregmap() { return x86_64_v2.WMASK; } + // Rare 3-address form + @Override public final void encoding( Encoding enc ) { + short dst = enc.reg(this ); // Also src1 + short src = enc.reg(in(1)); + enc.add1(x86_64_v2.rex(src, dst, 0)); + // opcode; 0x69 or 0x6B + enc.add1( 0x69 + (x86_64_v2.imm8(_imm) ? 2 : 0) ); + enc.add1( x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, dst, src) ); + // immediate(4 bytes) 32 bits or (1 byte)8 bits + if( x86_64_v2.imm8(_imm) ) enc.add1(_imm); + else enc.add4(_imm); + } + // General form: "addi dst += #imm" + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" * #").p(_imm); + } } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/NewX86.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/NewX86.java index aa81518..34198db 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/NewX86.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/NewX86.java @@ -3,7 +3,6 @@ import com.compilerprogramming.ezlang.compiler.*; import com.compilerprogramming.ezlang.compiler.codegen.*; import com.compilerprogramming.ezlang.compiler.nodes.*; -import com.compilerprogramming.ezlang.compiler.sontypes.SONTypeFunPtr; public class NewX86 extends NewNode implements MachNode { // A pre-zeroed chunk of memory. diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/RegX86.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/RegX86.java index 8a5e305..6a3838b 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/RegX86.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/RegX86.java @@ -8,6 +8,7 @@ public abstract class RegX86 extends MachConcreteNode { RegX86( Node add ) { super(add); } @Override public RegMask regmap(int i) { return x86_64_v2.RMASK; } @Override public RegMask outregmap() { return x86_64_v2.WMASK; } + @Override public RegMask killmap() { return x86_64_v2.FLAGS_MASK; } @Override public int twoAddress() { return 1; } abstract int opcode(); @Override public void encoding( Encoding enc ) { diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/SetX86.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/SetX86.java index ae9ff53..62126e8 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/SetX86.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/SetX86.java @@ -27,7 +27,7 @@ public class SetX86 extends MachConcreteNode implements MachNode { short dst = enc.reg(this ); // Optional rex, for dst - if( dst >= 8 ) enc.add1(x86_64_v2.rex(0, dst, 0)); + if( dst >= 4 ) enc.add1(x86_64_v2.rex(0, dst, 0, false)); enc.add1(0x0F); // opcode enc.add1(switch (_bop) { case "==" -> 0x94; // SETE @@ -39,7 +39,7 @@ public class SetX86 extends MachConcreteNode implements MachNode { enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, 0, dst)); // low 8 bites are set, now zero extend for next instruction - if( dst >= 8 ) enc.add1(x86_64_v2.rex(0, dst, 0)); + if( dst >= 4 ) enc.add1(x86_64_v2.rex(dst, dst, 0, false)); enc.add1(0x0F); // opcode enc.add1(0xB6); // opcode enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, dst, dst)); diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/SplitX86.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/SplitX86.java index 545d0f1..278dfb2 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/SplitX86.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/SplitX86.java @@ -1,14 +1,12 @@ package com.compilerprogramming.ezlang.compiler.nodes.cpus.x86_64_v2; import com.compilerprogramming.ezlang.compiler.SB; -import com.compilerprogramming.ezlang.compiler.Utils; import com.compilerprogramming.ezlang.compiler.codegen.*; import com.compilerprogramming.ezlang.compiler.nodes.FunNode; import com.compilerprogramming.ezlang.compiler.nodes.Node; import com.compilerprogramming.ezlang.compiler.nodes.SplitNode; -import com.compilerprogramming.ezlang.compiler.sontypes.SONType; -import com.compilerprogramming.ezlang.compiler.sontypes.SONTypeFloat; -import com.compilerprogramming.ezlang.compiler.sontypes.SONTypeInteger; +import com.compilerprogramming.ezlang.compiler.sontypes.TypeFloat; +import com.compilerprogramming.ezlang.compiler.sontypes.TypeInteger; public class SplitX86 extends SplitNode { SplitX86( String kind, byte round ) { super(kind,round, new Node[2]); } @@ -59,12 +57,12 @@ public class SplitX86 extends SplitNode { x86_64_v2.indirectAdr(0, (short)-1/*index*/, (short)x86_64_v2.RSP, off, 0, enc); return; } - StoreX86.encVal(enc, srcX ? SONTypeFloat.F64 : SONTypeInteger.BOT, (short)x86_64_v2.RSP, (short)-1/*index*/, src, off, 0); + StoreX86.encVal(enc, srcX ? TypeFloat.F64 : TypeInteger.BOT, (short)x86_64_v2.RSP, (short)-1/*index*/, src, off, 0); return; } if( src >= x86_64_v2.MAX_REG ) { int off = enc._fun.computeStackOffset(enc._code,src); - LoadX86.enc(enc, dstX ? SONTypeFloat.F64 : SONTypeInteger.BOT, dst, (short)x86_64_v2.RSP, (short)-1, off, 0); + LoadX86.enc(enc, dstX ? TypeFloat.F64 : TypeInteger.BOT, dst, (short)x86_64_v2.RSP, (short)-1, off, 0); return; } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/StoreX86.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/StoreX86.java index 243f48b..1fb8cd9 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/StoreX86.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/StoreX86.java @@ -2,11 +2,10 @@ import com.compilerprogramming.ezlang.compiler.SB; import com.compilerprogramming.ezlang.compiler.codegen.*; -import com.compilerprogramming.ezlang.compiler.nodes.ConstantNode; import com.compilerprogramming.ezlang.compiler.nodes.Node; import com.compilerprogramming.ezlang.compiler.nodes.StoreNode; -import com.compilerprogramming.ezlang.compiler.sontypes.SONType; -import com.compilerprogramming.ezlang.compiler.sontypes.SONTypeFloat; +import com.compilerprogramming.ezlang.compiler.sontypes.Type; + import java.util.BitSet; public class StoreX86 extends MemOpX86 { @@ -52,7 +51,7 @@ public class StoreX86 extends MemOpX86 { } // Non-immediate encoding - static void encVal( Encoding enc, SONType decl, short ptr, short idx, short src, int off, int scale ) { + static void encVal( Encoding enc, Type decl, short ptr, short idx, short src, int off, int scale ) { int log = decl.log_size(); // Float reg being stored if( src >= x86_64_v2.XMM_OFFSET ) { diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/TFPX86.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/TFPX86.java index 4861b8d..46e9e9c 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/TFPX86.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/TFPX86.java @@ -3,15 +3,13 @@ import com.compilerprogramming.ezlang.compiler.*; import com.compilerprogramming.ezlang.compiler.codegen.*; import com.compilerprogramming.ezlang.compiler.nodes.*; -import com.compilerprogramming.ezlang.compiler.nodes.cpus.riscv.riscv; -import com.compilerprogramming.ezlang.compiler.sontypes.SONType; -import com.compilerprogramming.ezlang.compiler.sontypes.SONTypeFunPtr; +import com.compilerprogramming.ezlang.compiler.sontypes.Type; // Function constants public class TFPX86 extends ConstantNode implements MachNode, RIPRelSize { TFPX86( ConstantNode con ) { super(con); } @Override public String op() { - return _con == SONType.NIL ? "xor" : "ldx"; + return _con == Type.NIL ? "xor" : "ldx"; } @Override public boolean isClone() { return true; } @Override public Node copy() { return new TFPX86(this); } @@ -19,13 +17,13 @@ public class TFPX86 extends ConstantNode implements MachNode, RIPRelSize { @Override public RegMask outregmap() { return x86_64_v2.WMASK; } // Zero-set uses XOR kills flags @Override public RegMask killmap() { - return _con == SONType.NIL ? x86_64_v2.FLAGS_MASK : null; + return _con == Type.NIL ? x86_64_v2.FLAGS_MASK : null; } @Override public void encoding( Encoding enc ) { short dst = enc.reg(this); // Short form for zero - if( _con==SONType.NIL ) { + if( _con==Type.NIL ) { // XOR dst,dst. Can skip REX is dst is low 8, makes this a 32b // xor, which will also zero the high bits. if( dst >= 8 ) enc.add1(x86_64_v2.rex(dst, dst, 0)); @@ -58,9 +56,10 @@ public class TFPX86 extends ConstantNode implements MachNode, RIPRelSize { // General form: "op\tdst=src+src" @Override public void asm(CodeGen code, SB sb) { String reg = code.reg(this); - if( _con == SONType.NIL ) + if( _con == Type.NIL ) sb.p(reg).p(",").p(reg); else _con.print(sb.p(reg).p(" = #")); } + @Override public boolean eq(Node n) { return this==n; } } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/TMPX86.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/TMPX86.java new file mode 100644 index 0000000..746379b --- /dev/null +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/TMPX86.java @@ -0,0 +1,35 @@ +package com.compilerprogramming.ezlang.compiler.nodes.cpus.x86_64_v2; + +import com.compilerprogramming.ezlang.compiler.SB; +import com.compilerprogramming.ezlang.compiler.codegen.*; +import com.compilerprogramming.ezlang.compiler.nodes.*; +import com.compilerprogramming.ezlang.compiler.sontypes.TypeMemPtr; + +public class TMPX86 extends ConstantNode implements MachNode, RIPRelSize{ + TMPX86(ConstantNode con ) { super(con); } + @Override public String op() { return "ldp"; } + @Override public RegMask regmap(int i) { return null; } + @Override public RegMask outregmap() { return x86_64_v2.WMASK; } + @Override public boolean isClone() { return true; } + @Override public Node copy() { return new TMPX86(this); } + + @Override public void encoding( Encoding enc ) { + short dst = enc.reg(this); + x86_64_v2.rexF(dst, 0, 0, true, enc); + enc.add1(0x8D).add1(x86_64_v2.modrm(x86_64_v2.MOD.INDIRECT, dst, 0b101)).add4(0); + enc.largeConstant(this,((TypeMemPtr)_con)._obj,7-4,2/*ELF encoding PC32*/); + } + + // Delta is from opcode start + @Override public byte encSize(int delta) { return (byte)7; } + + // Delta is from opcode start + @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { + enc.patch4(opStart+opLen-4,delta-opLen); + } + + @Override public void asm(CodeGen code, SB sb) { + _con.print(sb.p(code.reg(this)).p(" = #")); + } + @Override public boolean eq(Node n) { return this==n; } +} diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/UJmpX86.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/UJmpX86.java index d404bb5..7d05e25 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/UJmpX86.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/UJmpX86.java @@ -3,7 +3,7 @@ import com.compilerprogramming.ezlang.compiler.*; import com.compilerprogramming.ezlang.compiler.codegen.*; import com.compilerprogramming.ezlang.compiler.nodes.*; -import com.compilerprogramming.ezlang.compiler.sontypes.SONType; +import com.compilerprogramming.ezlang.compiler.sontypes.Type; import java.util.BitSet; // unconditional jump @@ -16,7 +16,7 @@ public class UJmpX86 extends CFGNode implements MachNode, RIPRelSize { } @Override public RegMask regmap(int i) {return null; } @Override public RegMask outregmap() { return null; } - @Override public SONType compute() { throw Utils.TODO(); } + @Override public Type compute() { throw Utils.TODO(); } @Override public Node idealize() { throw Utils.TODO(); } @Override public void encoding( Encoding enc ) { enc.jump(this,uctrl()); diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/x86_64_v2.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/x86_64_v2.java index 547abda..1133035 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/x86_64_v2.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/x86_64_v2.java @@ -43,6 +43,8 @@ public x86_64_v2( CodeGen code ) {} static RegMask XMASK = new RegMask(FP_BITS); static RegMask FLAGS_MASK = new RegMask(FLAGS); static RegMask RPC_MASK = new RegMask(RPC); + // Divide mask: exclude RDX:RAX + static RegMask DIV_MASK = new RegMask(RD_BITS & ~(1L<= tfp.nargs() ) return null; // Anti-dependence return switch( CodeGen.CODE._callingConv ) { case "SystemV" -> callSys5 (tfp,idx,maxArgSlot); case "Win64" -> callWin64(tfp,idx,maxArgSlot); @@ -197,7 +200,7 @@ static RegMask callInMask( SONTypeFunPtr tfp, int idx, int maxArgSlot ) { } // Maximum stack args used by this signature - @Override public short maxArgSlot( SONTypeFunPtr tfp ) { + @Override public short maxArgSlot( TypeFunPtr tfp ) { return switch( CodeGen.CODE._callingConv ) { case "SystemV" -> maxArgSlotSys5 (tfp); case "Win64" -> maxArgSlotWin64(tfp); @@ -230,16 +233,16 @@ static RegMask callInMask( SONTypeFunPtr tfp, int idx, int maxArgSlot ) { R09_MASK, }; - static RegMask callWin64(SONTypeFunPtr tfp, int idx, int maxArgSlot ) { + static RegMask callWin64(TypeFunPtr tfp, int idx, int maxArgSlot ) { // idx 2,3,4,5 passed in registers, with stack slot mirrors. // idx >= 6 passed on stack, starting at slot#1 (#0 reserved for RPC). if( idx >= 6 ) return new RegMask(MAX_REG+maxArgSlot+(idx-2)); - return tfp.arg(idx-2) instanceof SONTypeFloat + return tfp.arg(idx-2) instanceof TypeFloat ? XMMS8 [idx-2] : WIN64_CALL[idx-2]; } - static short maxArgSlotWin64(SONTypeFunPtr tfp) { + static short maxArgSlotWin64(TypeFunPtr tfp) { return (short)tfp.nargs(); } @@ -271,23 +274,23 @@ static short maxArgSlotWin64(SONTypeFunPtr tfp) { R09_MASK, }; - static RegMask callSys5(SONTypeFunPtr tfp, int idx, int maxArgSlot ) { + static RegMask callSys5(TypeFunPtr tfp, int idx, int maxArgSlot ) { // First 6 integers passed in registers: rdi,rsi,rdx,rcx,r08,r09 // First 8 floats passed in registers: xmm0-xmm7 int icnt=0, fcnt=0; // Count of ints, floats for( int i=2; i and(and); case BoolNode bool -> cmp(bool); case CProjNode c -> new CProjNode(c); - case CallEndNode cend -> new CallEndX86(cend); + case CallEndNode cend -> new CallEndMach(cend); case CallNode call -> call(call); - case CastNode cast -> new CastX86(cast); + case CastNode cast -> new CastMach(cast); case ConstantNode con -> con(con); case DivFNode divf -> new DivFX86(divf); case DivNode div -> new DivX86(div); @@ -362,7 +365,7 @@ public Node instSelect(Node n) { case ParmNode parm -> new ParmX86(parm); case PhiNode phi -> new PhiNode(phi); case ProjNode prj -> prj(prj); - case ReadOnlyNode read-> new ReadOnlyNode(read); + case ReadOnlyNode read-> new ReadOnlyMach(read); case ReturnNode ret -> new RetX86(ret, ret.fun()); case SarNode sar -> sar(sar); case ShlNode shl -> shl(shl); @@ -373,7 +376,7 @@ public Node instSelect(Node n) { case SubFNode subf -> new SubFX86(subf); case SubNode sub -> sub(sub); case ToFloatNode tfn -> i2f8(tfn); - case XCtrlNode x -> new ConstantNode(SONType.XCONTROL); + case XCtrlNode x -> new ConstantNode(Type.XCONTROL); case XorNode xor -> xor(xor); case LoopNode loop -> new LoopNode(loop); @@ -399,7 +402,7 @@ private Node add(AddNode add) { // Attempt a full LEA-style break down. // Returns one of AddX86, AddIX86, LeaX86, or LHS - if( rhs instanceof ConstantNode off2 && off2._con instanceof SONTypeInteger toff ) { + if( rhs instanceof ConstantNode off2 && off2._con instanceof TypeInteger toff ) { long imm = toff.value(); assert imm!=0; // Folded in peeps if( (int)imm != imm ) // Full 64bit immediate @@ -435,7 +438,7 @@ private Node _lea(Node add, Node base, Node idx, int off) { if( base instanceof ShlNode && !(idx instanceof ShlNode) ) throw Utils.TODO(); // Bug in canonicalization, should on RHS if( idx instanceof ShlNode shift && shift.in(2) instanceof ConstantNode shfcon && - shfcon._con instanceof SONTypeInteger tscale && 0 <= tscale.value() && tscale.value() <= 3 ) { + shfcon._con instanceof TypeInteger tscale && 0 <= tscale.value() && tscale.value() <= 3 ) { idx = shift.in(1); scale = ((int) tscale.value()); } @@ -447,13 +450,13 @@ private Node _lea(Node add, Node base, Node idx, int off) { private Node and(AndNode and) { - if( and.in(2) instanceof ConstantNode con && con._con instanceof SONTypeInteger ti && imm32(ti.value()) ) + if( and.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm32(ti.value()) ) return new AndIX86(and, (int)ti.value()); return new AndX86(and); } private Node call(CallNode call) { - return call.fptr() instanceof ConstantNode con && con._con instanceof SONTypeFunPtr tfp + return call.fptr() instanceof ConstantNode con && con._con instanceof TypeFunPtr tfp ? new CallX86(call, tfp) : new CallRX86(call); } @@ -487,11 +490,11 @@ private Node _cmp(BoolNode bool) { return new CmpMemX86(bool, address(ld), ld.ptr(), idx, off, scale, imm(lhs), val, true ); // Vs immediate - if( rhs instanceof ConstantNode con && con._con instanceof SONTypeInteger ti && imm32(ti.value()) ) + if( rhs instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm32(ti.value()) ) return new CmpIX86(bool, (int)ti.value(), false); // Operand swap compare; Set and Jmp need to swap `bop` - if( lhs instanceof ConstantNode con && con._con instanceof SONTypeInteger ti && imm32(ti.value()) ) + if( lhs instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm32(ti.value()) ) return new CmpIX86(bool, (int)ti.value(), swap=true); // x vs y @@ -499,20 +502,21 @@ private Node _cmp(BoolNode bool) { } private Node con( ConstantNode con ) { - if(!con._con.isConstant()) return new ConstantNode(con); // Default unknown caller inputs + if( !con._con.isConstant() ) + return new ConstantNode(con); // Default unknown caller inputs return switch (con._con) { - case SONTypeInteger ti -> new IntX86(con); - case SONTypeFloat tf -> new FltX86(con); - case SONTypeFunPtr tfp -> new TFPX86(con); - case SONTypeMemPtr tmp -> throw Utils.TODO(); - case SONTypeNil tn -> throw Utils.TODO(); - // TOP, BOTTOM, XCtrl, Ctrl, etc. Never any executable code. - case SONType t -> t == SONType.NIL ? new IntX86(con) : new ConstantNode(con); + case TypeInteger ti -> new IntX86(con); + case TypeFloat tf -> new FltX86(con); + case TypeFunPtr tfp -> new TFPX86(con); + case TypeMemPtr tmp -> new TMPX86(con); + case TypeNil tn -> throw Utils.TODO(); + // TOP, BOTTOM, XCtrl, Ctrl, etc. Never any executable code. + case Type t -> t == Type.NIL ? new IntX86(con) : new ConstantNode(con); }; } private Node i2f8(ToFloatNode tfn) { - assert tfn.in(1)._type instanceof SONTypeInteger ti; + assert tfn.in(1)._type instanceof TypeInteger ti; return new I2f8X86(tfn); } @@ -523,7 +527,7 @@ private Node jmp(IfNode iff) { String op = "!="; if( iff.in(1) instanceof BoolNode bool ) op = swap ? IfNode.swap(bool.op()) : bool.op(); else if( iff.in(1)==null ) op = "=="; // Never-node cutout - else iff.setDef(1, new BoolNode.NE(iff.in(1), new ConstantNode(SONTypeInteger.ZERO))); + else iff.setDef(1, new BoolNode.NE(iff.in(1), new ConstantNode(TypeInteger.ZERO))); return new JmpX86(iff, op); } @@ -532,13 +536,13 @@ private Node ld(LoadNode ld) { } private Node mul(MulNode mul) { - if( mul.in(2) instanceof ConstantNode con && con._con instanceof SONTypeInteger ti && imm32(ti.value()) ) + if( mul.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm32(ti.value()) ) return new MulIX86(mul, (int)ti.value()); return new MulX86(mul); } private Node or(OrNode or) { - if( or.in(2) instanceof ConstantNode con && con._con instanceof SONTypeInteger ti && imm32(ti.value()) ) + if( or.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm32(ti.value()) ) return new OrIX86(or, (int)ti.value()); return new OrX86(or); } @@ -548,19 +552,19 @@ private Node prj( ProjNode prj ) { } private Node sar(SarNode sar) { - if( sar.in(2) instanceof ConstantNode con && con._con instanceof SONTypeInteger ti && imm8(ti.value())) + if( sar.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm8(ti.value())) return new SarIX86(sar, (int)(ti.value() & 0xff) ); return new SarX86(sar); } private Node shl(ShlNode shl) { - if( shl.in(2) instanceof ConstantNode con && con._con instanceof SONTypeInteger ti && imm8(ti.value())) + if( shl.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm8(ti.value())) return new ShlIX86(shl, (int)(ti.value() & 0xff) ); return new ShlX86(shl); } private Node shr( ShrNode shr ) { - if( shr.in(2) instanceof ConstantNode con && con._con instanceof SONTypeInteger ti && imm8(ti.value()) ) + if( shr.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm8(ti.value()) ) return new ShrIX86(shr, (int)(ti.value() & 0xff) ); return new ShrX86(shr); } @@ -586,13 +590,13 @@ private static boolean stld_match(StoreNode st, LoadNode ld ) { private Node sub (SubNode sub ){ - return sub.in(2) instanceof ConstantNode con && con._con instanceof SONTypeInteger ti + return sub.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti ? new AddIX86(sub, (int)-ti.value()) : new SubX86(sub); } private Node xor (XorNode xor){ - if( xor.in(2) instanceof ConstantNode con && con._con instanceof SONTypeInteger ti && imm32(ti.value()) ) + if( xor.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm32(ti.value()) ) return new XorIX86(xor, (int)ti.value()); return new XorX86(xor); } @@ -608,18 +612,18 @@ private N address(N mop) { Node base = mop.ptr(); // Skip/throw-away a ReadOnly, only used to typecheck if(base instanceof ReadOnlyNode read) base = read.in(1); - assert !(base instanceof AddNode) && base._type instanceof SONTypeMemPtr; // Base ptr always, not some derived - if(mop.off() instanceof AddNode add && add.in(2) instanceof ConstantNode con && con._con instanceof SONTypeInteger ti) { + assert !(base instanceof AddNode) && base._type instanceof TypeMemPtr; // Base ptr always, not some derived + if(mop.off() instanceof AddNode add && add.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti) { off = (int) ti.value(); assert off == ti.value(); // In 32-bit range idx = add.in(1); if(idx instanceof ShlNode shift && shift.in(2) instanceof ConstantNode shfcon && - shfcon._con instanceof SONTypeInteger tscale && 0 <= tscale.value() && tscale.value() <= 3) { + shfcon._con instanceof TypeInteger tscale && 0 <= tscale.value() && tscale.value() <= 3) { idx = shift.in(1); scale = (int) tscale.value(); } } else { - if(mop.off() instanceof ConstantNode con && con._con instanceof SONTypeInteger ti) { + if(mop.off() instanceof ConstantNode con && con._con instanceof TypeInteger ti) { off = (int) ti.value(); assert off == ti.value(); // In 32-bit range } else { @@ -631,7 +635,7 @@ private N address(N mop) { private int imm( Node xval ) { assert val == null && imm == 0; - if( xval instanceof ConstantNode con && con._con instanceof SONTypeInteger ti) { + if( xval instanceof ConstantNode con && con._con instanceof TypeInteger ti) { val = null; imm = (int) ti.value(); assert imm == ti.value(); // In 32-bit range diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/print/ASMPrinter.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/print/ASMPrinter.java index 1a93013..0c5c680 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/print/ASMPrinter.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/print/ASMPrinter.java @@ -1,5 +1,6 @@ package com.compilerprogramming.ezlang.compiler.print; +import com.compilerprogramming.ezlang.compiler.Ary; import com.compilerprogramming.ezlang.compiler.codegen.CodeGen; import com.compilerprogramming.ezlang.compiler.SB; import com.compilerprogramming.ezlang.compiler.codegen.Encoding; @@ -20,54 +21,71 @@ public static SB print(SB sb, CodeGen code) { if( code._cfg.at(i) instanceof FunNode fun ) iadr = print(iadr,sb,code,fun,i); - // Skip padding - while( ((iadr+7) & -8) > iadr ) - iadr++; - // constant pool + iadr = (iadr+15)&-16; // pad to 16 Encoding enc = code._encoding; - if( enc!=null && !enc._bigCons.isEmpty() ) { - iadr = (iadr+15)&-16; // pad to 16 - HashSet targets = new HashSet<>(); + if( enc!=null && !enc._bigCons.isEmpty() && iadr < enc._bits.size() ) { + // radix sort the big constants by alignment + Ary[] raligns = new Ary[5]; + for( Node op : enc._bigCons.keySet() ) { + Encoding.Relo relo = enc._bigCons.get(op); + int align = relo._t.alignment(); + Ary relos = raligns[align]==null ? (raligns[align]=new Ary<>( Encoding.Relo.class)) : raligns[align]; + relos.add(relo); + } + + HashSet targets = new HashSet<>(); sb.p("--- Constant Pool ------").nl(); - // By log size - for( int log = 3; log >= 0; log-- ) { - for( Node op : enc._bigCons.keySet() ) { - Encoding.Relo relo = enc._bigCons.get(op); + + // By alignment + for( int align = 4; align >= 0; align-- ) { + Ary relos = raligns[align]; + if( relos == null ) continue; + for( Encoding.Relo relo : relos ) { if( targets.contains(relo._t) ) continue; targets.add(relo._t); - if( relo._t.log_size()==log ) { - sb.hex2(iadr).p(" "); - if( relo._t instanceof SONTypeTuple tt ) { - for( SONType tx : tt._types ) { - switch( log ) { - case 0: sb.hex1(enc.read1(iadr)); break; - case 1: sb.hex2(enc.read2(iadr)); break; - case 2: sb.hex4(enc.read4(iadr)); break; - case 3: sb.hex8(enc.read8(iadr)); break; - } - iadr += (1< { + for( Type tx : tt._types ) { + pN(enc,sb,iadr,align).p(" "); + iadr += (1< { + int sz = ts.size(); + int log = 1< { + pN(enc,sb,iadr,align).fix(9-(1<