diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/IterPeeps.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/IterPeeps.java index f58ae9f..c18aa90 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/IterPeeps.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/IterPeeps.java @@ -49,6 +49,7 @@ public class IterPeeps { public IterPeeps( long seed ) { _work = new WorkList<>(seed); } + @SuppressWarnings("unchecked") public N add( N n ) { return (N)_work.push(n); } public void addAll( Ary ary ) { _work.addAll(ary); } @@ -126,6 +127,7 @@ private boolean progressOnList(CodeGen code) { * Classic WorkList, with a fast add/remove, dup removal, random pull. * The Node's nid is used to check membership in the worklist. */ + @SuppressWarnings("unchecked") public static class WorkList { private Node[] _es; diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/Coalesce.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/Coalesce.java index a5b9183..47c75e6 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/Coalesce.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/Coalesce.java @@ -10,20 +10,6 @@ abstract public class Coalesce { public static boolean coalesce( int round, RegAlloc alloc ) { - // Convert the 2-D array of bits (a 1-D array of BitSets) into an - // adjacency matrix. - int maxlrg = alloc._LRGS.length; - for( int i=1; i=0; lrg=ifg.nextSetBit(lrg+1) ) { - LRG lrg1 = alloc._LRGS[lrg]; - lrg0.addNeighbor(lrg1); - lrg1.addNeighbor(lrg0); - } - } - } // Walk all the splits, looking for coalesce chances boolean progress = false; @@ -37,7 +23,7 @@ public static boolean coalesce( int round, RegAlloc alloc ) { if( v1 != v2 ) { LRG ov1 = v1, ov2 = v2; // Get the smaller neighbor count in v1 - if( (v1._adj==null ? 0 : v1._adj._len) > (v2._adj==null ? 0 : v2._adj._len) ) + if( v1.nadj() > v2.nadj() ) { v1 = v2; v2 = alloc.lrg(n); } int v2len = v2._adj==null ? 0 : v2._adj._len; // See that they do not conflict (coalescing would make a self-conflict) @@ -58,9 +44,9 @@ public static boolean coalesce( int round, RegAlloc alloc ) { // Most constrained mask RegMask mask = v1._mask==v2._mask ? v1._mask : v1._mask.copy().and(v2._mask); // Check for capacity - if( (v2._adj==null ? 0 : v2._adj._len) >= mask.size() ) { + if( v2.nadj() >= mask.size() ) { // Fails capacity, will not be trivial colorable - v2._adj.setLen(v2len); + if( v2._adj!=null ) v2._adj.setLen(v2len); continue; } 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 522cfd3..22e05c3 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 @@ -11,7 +11,9 @@ import java.util.HashMap; import java.util.IdentityHashMap; +@SuppressWarnings("unchecked") public class CodeGen { + public static final String PORTS = "com.compilerprogramming.ezlang.compiler.nodes.cpus"; // Last created CodeGen as a global; used all over to avoid passing about a // "context". public static CodeGen CODE; @@ -187,7 +189,8 @@ public CodeGen typeCheck() { // Convert to target hardware nodes public int _tInsSel; - public CodeGen instSelect( String base, String cpu, String callingConv ) { + 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.TypeCheck.ordinal(); _phase = Phase.InstSelect; @@ -313,16 +316,21 @@ public String reg(Node n) { // --------------------------- // Encoding public int _tEncode; + public boolean _JIT; public Encoding _encoding; - public CodeGen encode() { + public CodeGen encode(boolean jit) { assert _phase == Phase.RegAlloc; _phase = Phase.Encoding; long t0 = System.currentTimeMillis(); _encoding = new Encoding(this); + _JIT = jit; _encoding.encode(); _tEncode = (int)(System.currentTimeMillis() - t0); return this; } + public CodeGen encode() { + return encode(false); + } // Encoded binary, no relocation info public byte[] binary() { return _encoding.bits(); } @@ -331,12 +339,13 @@ public CodeGen encode() { public CodeGen exportELF(String fname) throws IOException { assert _phase == Phase.Encoding; _phase = Phase.Export; - ElfFile obj = new ElfFile(this); - obj.export(fname); + if( fname == null ) new LinkMem(this).link(); // In memory patching + else new ElfFile(this).export(fname); // External ELF file return this; } // --------------------------- + public boolean _asmLittle=true; SB asm(SB sb) { return ASMPrinter.print(sb,this); } public String asm() { return asm(new 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 eee43a1..490b921 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 @@ -4,14 +4,12 @@ import com.compilerprogramming.ezlang.compiler.nodes.*; import com.compilerprogramming.ezlang.compiler.sontypes.*; -import java.util.Map; -import java.util.HashMap; +import java.io.*; + import java.nio.ByteBuffer; import java.nio.ByteOrder; -import java.io.IOException; -import java.io.FileOutputStream; -import java.io.ByteArrayOutputStream; -import java.io.BufferedOutputStream; +import java.util.HashMap; +import java.util.Map; public class ElfFile { @@ -69,6 +67,10 @@ public static class Symbol { // top 4bits are the "bind", bottom 4 are "type" int _info; + // bind 1011 + // 00001111 + // 10110000 + Symbol(String name, int parent, int bind, int type) { _name = name; _parent = parent; @@ -78,6 +80,7 @@ public static class Symbol { void writeHeader(ByteBuffer out) { out.putInt(_name_pos); // name out.put((byte) _info); // info + // default visibility out.put((byte) 0); // other out.putShort((short) _parent); // shndx out.putLong(_value); // value @@ -117,7 +120,7 @@ void writeHeader(ByteBuffer out) { out.putLong(size()); // size out.putInt(_link); // link out.putInt(_info); // info - out.putLong(1); // addralign + out.putLong(16); // addralign if (_type == 2) { out.putLong(SYMBOL_SIZE);// entsize } else if (_type == 4) { @@ -140,7 +143,7 @@ public static class SymbolSection extends Section { } @Override - void writeHeader(ByteBuffer out) { + void writeHeader(ByteBuffer out) { // points to string table section _link = 1; @@ -159,23 +162,22 @@ void push(Symbol s) { } @Override - void write(ByteBuffer out) { + void write(ByteBuffer out) { + // Index 0 both designates the first entry in the table and serves as the undefined symbol index for( int i = 0; i < SYMBOL_SIZE/4; i++ ) { out.putInt(0); } - int num=1; + // index is already set for( Symbol s : _loc ) { - s._index = num++; s.writeHeader(out); } for( Symbol s : _symbols ) { - s._index = num++; s.writeHeader(out); } } @Override - int size() { + int size() { return (1 + _symbols.len() + _loc.len()) * SYMBOL_SIZE; } } @@ -210,54 +212,21 @@ private void pushSection(Section s) { s._index = _sections._len; } + /* creates function and stores where it starts*/ private final HashMap _funcs = new HashMap<>(); private void encodeFunctions(SymbolSection symbols, DataSection text) { - int func_start = 0; for( int i=0; i<_code._cfg._len; i++ ) { - Node bb = _code._cfg.at(i); - if( bb instanceof FunNode f ) { - // skip until the function ends - while( !(_code._cfg.at(i) instanceof ReturnNode) ) { - i++; - } - - Node r = _code._cfg.at(i); - int end = _code._encoding._opStart[r._nid] + _code._encoding._opLen[r._nid]; - - Symbol func = new Symbol(f._name, text._index, SYM_BIND_GLOBAL, SYM_TYPE_FUNC); - func._size = end - func_start; - func._value = func_start; - symbols.push(func); - _funcs.put(f.sig(), func); - - // next function starts where the last one ends - func_start = end; - } - } - } - - public final HashMap _bigCons = new HashMap<>(); - private void encodeConstants(SymbolSection symbols, DataSection rdata) { - int cnt = 0; - for (Map.Entry e : _code._encoding._bigCons.entrySet()) { - if (_bigCons.get(e.getValue()) != null) { - continue; - } - - Symbol glob = new Symbol("GLOB$"+cnt, rdata._index, SYM_BIND_GLOBAL, SYM_TYPE_FUNC); - glob._value = rdata._contents.size(); - symbols.push(glob); - - SONType t = e.getValue(); - if ( t instanceof SONTypeFloat tf ) { - write8(rdata._contents, Double.doubleToLongBits(tf._con)); - } else { - throw Utils.TODO(); - } - - glob._size = rdata._contents.size() - glob._value; - _bigCons.put(e.getValue(), glob); - cnt++; + if( !(_code._cfg.at(i) instanceof FunNode fun) ) continue; + // skip until the function ends + while( !(_code._cfg.at(i) instanceof ReturnNode ret) ) + i++; + int end = _code._encoding._opStart[ret._nid] + _code._encoding._opLen[ret._nid]; + + Symbol func = new Symbol(fun._name, text._index, SYM_BIND_GLOBAL, SYM_TYPE_FUNC); + func._value = _code._encoding._opStart[fun._nid]; + func._size = end - func._value; + symbols.push(func); + _funcs.put(fun.sig(), func); } } @@ -271,67 +240,90 @@ public void export(String fname) throws IOException { SymbolSection symbols = new SymbolSection(".symtab", 2 /* SHT_STRTAB */); pushSection(symbols); + // zero flag by default // we've already constructed this entire section in the encoding phase DataSection text = new DataSection(".text", 1 /* SHT_PROGBITS */, _code._encoding._bits); text._flags = SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR; pushSection(text); - DataSection rdata = new DataSection(".rodata", 1 /* SHT_PROGBITS */); + // Build and write constant pool + Encoding.BAOS cpool = new Encoding.BAOS(); + Encoding enc = _code._encoding; + enc.writeConstantPool(cpool,false); + DataSection rdata = new DataSection(".rodata", 1 /* SHT_PROGBITS */, cpool); rdata._flags = SHF_ALLOC; pushSection(rdata); // populate function symbols encodeFunctions(symbols, text); - // populate big constants - // encodeConstants(symbols, rdata); + + int idx = 1; + for( Section s : _sections ) { + Symbol sym = new Symbol(s._name, idx++, SYM_BIND_LOCAL, SYM_TYPE_SECTION); + // we can reuse the same name pos from the actual section + sym._name_pos = s._name_pos; + sym._size = s.size(); + symbols.push(sym); + } + + // calculate local index + int num = 1; + for( Symbol s : symbols._loc ) + s._index = num++; + // extra space for .rela.text + 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 */); - for( Node n : _code._encoding._externals.keySet()) { + for( Node n : enc._externals.keySet()) { int nid = n._nid; - String extern = _code._encoding._externals.get(n); - int sym_id = _funcs.get(extern)._index; - int offset = _code._encoding._opStart[nid] + _code._encoding._opLen[nid] - 4; + String extern = enc._externals.get(n); + + Symbol sym = new Symbol(extern, 0, SYM_BIND_GLOBAL, SYM_TYPE_NOTYPE); + sym._index = start_global++; + symbols.push(sym); + + int offset = enc._opStart[nid] + enc._opLen[nid] - 4; // u64 offset write8(text_rela._contents, offset); // u64 info - write8(text_rela._contents, ((long)sym_id << 32L) | 4L /* PLT32 */); + write8(text_rela._contents, ((long)sym._index << 32L) | 4L /* PLT32 */); // i64 addend write8(text_rela._contents, -4); } - // relocations to constants - if (false) for (Map.Entry e : _code._encoding._bigCons.entrySet()) { - int nid = e.getKey()._nid; - int sym_id = _bigCons.get(e.getValue())._index; - int offset = _code._encoding._opStart[nid] + _code._encoding._opLen[nid] - 4; - // u64 offset - write8(text_rela._contents, offset); - // u64 info - write8(text_rela._contents, ((long)sym_id << 32L) | 1L /* PC32 */); - // i64 addend + // 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); + glob._value = relo._target; + glob._size = 1 << relo._t.log_size(); + glob._index = bigConIdx++; + symbols.push(glob); + write8(text_rela._contents, relo._opStart+relo._off); + write8(text_rela._contents, ((long)glob._index << 32L) | relo._elf ); write8(text_rela._contents, -4); } + text_rela._flags = SHF_INFO_LINK; text_rela._link = 2; text_rela._info = text._index; pushSection(text_rela); + 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(); + symbols.push(sym); + // populate string table for( Section s : _sections ) { s._name_pos = writeCString(strtab, s._name); } for( Symbol s : symbols._symbols ) { s._name_pos = writeCString(strtab, s._name); } for( Symbol s : symbols._loc ) { s._name_pos = writeCString(strtab, s._name); } - int idx = 1; - for( Section s : _sections ) { - Symbol sym = new Symbol(s._name, idx++, SYM_BIND_LOCAL, SYM_TYPE_SECTION); - // we can reuse the same name pos from the actual section - sym._name_pos = s._name_pos; - sym._size = s.size(); - symbols.push(sym); - } - int size = 64; // ELF header // size of all section data for( Section s : _sections ) { @@ -379,7 +371,10 @@ public void export(String fname) throws IOException { } assert out.position() == size; - BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(fname)); + File file = new File(fname); + if( file.getParentFile()!=null ) + file.getParentFile().mkdirs(); + BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file)); bos.write(out.array()); bos.close(); } 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 a30447d..6696e1c 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 @@ -44,6 +44,20 @@ public static class BAOS extends ByteArrayOutputStream { public int [] _opStart; // Start of opcodes, by _nid public byte[] _opLen; // Length of opcodes, by _nid + // Big Constant relocation info. + public static class Relo { + public final Node _op; + public final SONType _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 ) { + _op=op; _t=t; _off=off; _elf=elf; + } + } + public final HashMap _bigCons = new HashMap<>(); + Encoding( CodeGen code ) { _code = code; } // Shortcut to the defining register @@ -51,26 +65,17 @@ public short reg(Node n) { return _code._regAlloc.regnum(n); } - public Encoding add1( int op ) { _bits.write(op); return this; } - - public void add2( int op ) { - _bits.write(op ); - _bits.write(op>> 8); - } - // Little endian write of a 32b opcode - public void add4( int op ) { - _bits.write(op ); - _bits.write(op>> 8); - _bits.write(op>>16); - _bits.write(op>>24); + public int read1(int idx) { + byte[] buf = _bits.buf(); + return (buf[idx]&0xFF); } - public void add8( long i64 ) { - add4((int) i64 ); - add4((int)(i64>>32)); + public int read2(int idx) { + byte[] buf = _bits.buf(); + return (buf[idx]&0xFF) | (buf[idx+1]&0xFF) <<8; } public int read4(int idx) { byte[] buf = _bits.buf(); - return buf[idx] | (buf[idx+1]&0xFF) <<8 | (buf[idx+2]&0xFF)<<16 | (buf[idx+3]&0xFF)<<24; + return (buf[idx]&0xFF) | (buf[idx+1]&0xFF) <<8 | (buf[idx+2]&0xFF)<<16 | (buf[idx+3]&0xFF)<<24; } public long read8(int idx) { return (read4(idx) & 0xFFFFFFFFL) | read4(idx+4); @@ -88,11 +93,32 @@ public void patch4( int idx, int val ) { buf[idx+3] = (byte)(val>>24); } - void pad8() { - while( (_bits.size()+7 & -8) > _bits.size() ) - _bits.write(0); + static void padN(int n, BAOS bits) { + while( (bits.size()+n-1 & -n) > bits.size() ) + bits.write(0); } + // Convenience for writing log-N + static void addN( int log, SONType t, BAOS bits ) { + long x = t instanceof SONTypeInteger ti + ? ti.value() + : log==3 + ? Double.doubleToRawLongBits( ((SONTypeFloat)t).value()) + : Float.floatToRawIntBits((float)((SONTypeFloat)t).value()); + addN(log,x,bits); + } + static void addN( int log, long x, BAOS bits ) { + for( int i=0; i < 1<>= 8; + } + } + + public Encoding add1( int op ) { addN(0,op,_bits); return this; } + public Encoding add2( int op ) { addN(1,op,_bits); return this; } + public Encoding add4( int op ) { addN(2,op,_bits); return this; } + public Encoding add8(long op ) { addN(3,op,_bits); return this; } + // Nodes need "relocation" patching; things done after code is placed. // Record src and dst Nodes. @@ -108,9 +134,7 @@ public Encoding relo( ConstantNode con ) { return this; } public void jump( CFGNode jmp, CFGNode dst ) { - while( dst.nOuts() == 1 ) // Skip empty blocks - dst = dst.uctrl(); - _internals.put(jmp,dst); + _internals.put(jmp,dst.uctrlSkipEmpty()); } @@ -122,12 +146,11 @@ public Encoding external( Node call, String extern ) { // Store t as a 32/64 bit constant in the code space; generate RIP-relative // addressing to load it - - public final HashMap _bigCons = new HashMap<>(); - public final HashMap _cpool = new HashMap<>(); - public void largeConstant( Node relo, SONType t ) { + public void largeConstant( Node relo, SONType t, int off, int elf ) { assert t.isConstant(); - _bigCons.put(relo,t); + assert (byte)off == off; + assert (byte)elf == elf; + _bigCons.put(relo,new Relo(relo,t,(byte)off,(byte)elf)); } void encode() { @@ -141,16 +164,13 @@ void encode() { // Record opcode start and length. writeEncodings(); - // Write any large constants into a constant pool; they - // are accessed by RIP-relative addressing. - writeConstantPool(); - // Short-form RIP-relative support: replace long encodings with short // encodings and compact the code, changing all the offsets. compactShortForm(); // Patch RIP-relative and local encodings now. patchLocalRelocations(); + } // Basic block layout: invert branches to keep blocks in-order; insert @@ -161,8 +181,11 @@ private void basicBlockLayout() { Ary rpo = new Ary<>(CFGNode.class); BitSet visit = _code.visit(); for( Node n : _code._start._outputs ) - if( n instanceof FunNode fun ) + if( n instanceof FunNode fun ) { + int x = rpo._len; _rpo_cfg(fun, visit, rpo); + assert rpo.at(x) instanceof ReturnNode; + } rpo.add(_code._start); // Reverse in-place @@ -186,9 +209,14 @@ private void _rpo_cfg(CFGNode bb, BitSet visit, Ary rpo) { // If the *next* BB has already been visited, we may need an // unconditional jump here if( visit.get(next._nid) && !(next instanceof StopNode) ) { - // If all the blocks, in RPO order, to our target - // are empty, we will fall in and not need a jump. - if( next instanceof LoopNode || !isEmptyBackwardsScan(rpo,next) ) { + boolean needJump = next instanceof LoopNode + // If backwards to a loop, and the block has statements, + // will need a jump. Empty blocks can just backwards branch. + ? (bb.nOuts()>1) + // Forwards jump. If all the blocks, in RPO order, to our + // target are empty, we will fall in and not need a jump. + : !isEmptyBackwardsScan(rpo,next); + if( needJump ) { CFGNode jmp = _code._mach.jump(); jmp.setDefX(0,bb); next.setDef(next._inputs.find(bb),jmp); @@ -224,15 +252,27 @@ private void _rpo_cfg(CFGNode bb, BitSet visit, Ary rpo) { t.invert(); f.invert(); CProjNode tmp=f; f=t; t=tmp; // Swap t/f + int d=tld; tld=fld; fld=d; // Swap depth } - // Always visit the False side last (so True side first), so that + // Whichever side is visited first becomes last in the RPO. With + // no loops, visit the False side last (so True side first) so that // when the False RPO visit returns, the IF is immediately next. // When the RPO is reversed, the fall-through path will always be // following the IF. - _rpo_cfg(t,visit,rpo); - _rpo_cfg(f,visit,rpo); + + // If loops are involved, attempt to keep them in a line. Visit + // the exits first, so they follow the loop body when the order gets + // reversed. + if( fld < tld || (fld==tld && f.nOuts()==1) ) { + _rpo_cfg(f,visit,rpo); + _rpo_cfg(t,visit,rpo); + } else { + _rpo_cfg(t,visit,rpo); + _rpo_cfg(f,visit,rpo); + } } + assert rpo._len>0 || bb instanceof ReturnNode; rpo.add(bb); } @@ -253,6 +293,7 @@ private void writeEncodings() { if( !(bb instanceof MachNode mach0) ) _opStart[bb._nid] = _bits.size(); else if( bb instanceof FunNode fun ) { + padN(16,_bits); _fun = fun; // Currently encoding function _opStart[bb._nid] = _bits.size(); mach0.encoding( this ); @@ -266,44 +307,7 @@ else if( bb instanceof FunNode fun ) { } } } - pad8(); - } - - // Write the constant pool - private void writeConstantPool() { - // TODO: Check for cpool dups - HashSet ts = new HashSet<>(); - for( SONType t : _bigCons.values() ) { - if( ts.contains(t) ) - throw Utils.TODO(); // Dup! Compress! - ts.add(t); - } - - // Write the 8-byte constants - for( Node relo : _bigCons.keySet() ) { - SONType t = _bigCons.get(relo); - if( t.log_size()==3 ) { - // Map from relo to constant start - _cpool.put(relo,_bits.size()); - long x = t instanceof SONTypeInteger ti - ? ti.value() - : Double.doubleToRawLongBits(((SONTypeFloat)t).value()); - add8(x); - } - } - - // Write the 4-byte constants - for( Node relo : _bigCons.keySet() ) { - SONType t = _bigCons.get(relo); - if( t.log_size()==2 ) { - // Map from relo to constant start - _cpool.put(relo,_bits.size()); - int x = t instanceof SONTypeInteger ti - ? (int)ti.value() - : Float.floatToRawIntBits((float)((SONTypeFloat)t).value()); - add4(x); - } - } + padN(16,_bits); } // Short-form RIP-relative support: replace short encodings with long @@ -327,9 +331,14 @@ private void compactShortForm() { slide = 0; for( int i=0; i ts = new HashSet<>(); + for( Relo t : _bigCons.values() ) { + if( ts.contains(t) ) + throw Utils.TODO(); // Dup! Compress! + ts.add(t); + } + padN(16,bits); + + // 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 + relo._target = bits.size(); + 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); + // 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); + } + } + } + } + + // Patch local encodings now - private void patchLocalRelocations() { + void patchLocalRelocations() { // Walk the local code-address relocations for( Node src : _internals.keySet() ) { - Node dst = _internals.get(src); + Node dst = _internals.get(src); int target = _opStart[dst._nid]; int start = _opStart[src._nid]; ((RIPRelSize)src).patch(this, start, _opLen[src._nid], target - start); } - - for( Node src : _cpool.keySet() ) { - int target = _cpool.get(src); - int start = _opStart[src._nid]; - ((RIPRelSize)src).patch(this, start, _opLen[src._nid], target - start); - } - } - - - // Actual stack layout is up to each CPU. - // X86, with too many args & spills: - // | CALLER | - // | argN | // slot 1, required by callER - // +--------+ - // | RPC | // slot 0, required by callER - // | callee | // slot 3, callEE - // | callee | // slot 2, callEE - // | PAD16 | - // +--------+ - - // RISC/ARM, with too many args & spills: - // | CALLER | - // | argN | // slot 0, required by callER - // +--------+ - // | callee | // slot 3, callEE: might be RPC - // | callee | // slot 2, callEE - // | callee | // slot 1, callEE - // | PAD16 | - // +--------+ - private void frameSize() { - for( Node n : _code._start.outs() ) { - if( n instanceof FunNode fun ) { - throw Utils.TODO(); - } - } } } 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 f0af74b..86712da 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 @@ -24,7 +24,7 @@ public static void buildCFG( CodeGen code ) { schedEarly(code); // Break up shared global constants by functions - breakUpGlobalConstants(code); + breakUpGlobalConstants(code._start); code._visit.clear(); schedLate (code); @@ -45,23 +45,28 @@ private static void _rpo_cfg(CFGNode def, Node use, BitSet visit, Ary r } // Break up shared global constants by functions - private static void breakUpGlobalConstants( CodeGen code ) { + private static void breakUpGlobalConstants( Node start ) { // For all global constants - for( int i=0; i< code._start.nOuts(); i++ ) { - Node con = code._start.out(i); + for( int i=0; i< start.nOuts(); i++ ) { + Node con = start.out(i); if( con instanceof MachNode mach && mach.isClone() ) { + breakUpGlobalConstants(con); // While constant has users in different functions while( true ) { // Find a function user, and another function FunNode fun = null; boolean done=true; for( Node use : con.outs() ) { - FunNode fun2 = use.cfg0().fun(); + FunNode fun2 = use instanceof ReturnNode ret ? ret.fun() : use.cfg0().fun(); if( fun==null || fun==fun2 ) fun=fun2; else { done=false; break; } } // Single function user, so this constant is not shared - if( done ) { i--; con.setDef(0,fun); break; } + if( done ) { + if( con.in(0)==start ) i--; + con.setDef(0,fun); + break; + } // Move function users to a private constant Node con2 = mach.copy(); // Private constant clone con2._inputs.set(0,null); // Preserve edge invariants from clone @@ -226,6 +231,7 @@ private static CFGNode use_block(Node n, Node use, CFGNode[] late) { // Least loop depth first, then largest idepth private static boolean better( CFGNode lca, CFGNode best ) { return lca.loopDepth() < best.loopDepth() || + lca instanceof NeverNode || (lca.idepth() > best.idepth() || best instanceof IfNode); } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/IFG.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/IFG.java index 38741ad..a67cf16 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/IFG.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/IFG.java @@ -78,6 +78,8 @@ public static boolean build( int round, RegAlloc alloc ) { while( !WORK.isEmpty() ) do_block(round,alloc,WORK.pop()); + if( alloc.success() ) + convert2DAdjacency(alloc); return alloc.success(); } @@ -265,6 +267,24 @@ private static void mergeLiveOut( RegAlloc alloc, CFGNode priorbb, int i ) { } + static void convert2DAdjacency( RegAlloc alloc ) { + // Convert the 2-D array of bits (a 1-D array of BitSets) into an + // adjacency matrix. + int maxlrg = alloc._LRGS.length; + for( int i=1; i=0; lrg=ifg.nextSetBit(lrg+1) ) { + LRG lrg1 = alloc._LRGS[lrg]; + lrg0.addNeighbor(lrg1); + lrg1.addNeighbor(lrg0); + } + } + } + } + + // ------------------------------------------------------------------------ // Color the inference graph. @@ -446,35 +466,39 @@ private static short biasColor( RegAlloc alloc, LRG lrg, short reg, RegMask mask if( mask.size1() ) return reg; // Check chain of splits up the def-chain. Take first allocated // register, and if it's available in the mask, take it. - Node defSplit = lrg._splitDef, useSplit = lrg._splitUse; - int tidx, cnt=0; + Node def = lrg._splitDef, use = lrg._splitUse; + int tidx=0, cnt=0; - while( (tidx=biasable(defSplit)) != 0 || biasable(useSplit) != 0 ) { + while( def != null || use != null ) { if( cnt++ > 10 ) break; - if( tidx != 0 ) { - short bias = biasColor( alloc, defSplit, mask ); + if( def != null ) { + short bias = biasColor( alloc, def, mask ); if( bias >= 0 ) return bias; // Good bias - if( bias == -2 ) defSplit = null; // Kill this side, no more searching - } else defSplit = null; + if( bias == -2 ) def = null; // Kill this side, no more searching + else if( (tidx=biasable(def)) == 0 ) def = null; + } - if( biasable(useSplit) != 0 ) { - short bias = biasColor( alloc, useSplit, mask ); + if( use != null ) { + short bias = biasColor( alloc, use, mask ); if( bias >= 0 ) return bias; // Good bias - if( bias == -2 ) useSplit = null; // Kill this side, no more searching - } else useSplit = null; + if( bias == -2 ) use = null; // Kill this side, no more searching + else if( biasable(use)==0 ) use = null; + } - if( defSplit != null ) { - short bias = biasColorNeighbors( alloc, defSplit, mask ); + if( def != null ) { + short bias = biasColorNeighbors( alloc, def, mask ); if( bias >= 0 ) return bias; // Advance def side - defSplit = defSplit.in(tidx); + def = def.in(tidx); + if( alloc.lrg(def)==null ) def=null; } - if( useSplit != null ) { - short bias = biasColorNeighbors( alloc, useSplit, mask ); + if( use != null ) { + short bias = biasColorNeighbors( alloc, use, mask ); if( bias >= 0 ) return bias; - useSplit = useSplit.out(0); + use = use.out(0); + if( biasable(use)==0 ) use=null; } } @@ -483,7 +507,7 @@ private static short biasColor( RegAlloc alloc, LRG lrg, short reg, RegMask mask private static int biasable(Node split) { if( split instanceof SplitNode ) return 1; // Yes biasable, advance is slot 1 - if( split instanceof PhiNode ) return 1; // Yes biasable, advance is slot 1 + if( split instanceof PhiNode phi ) return phi.region() instanceof LoopNode ? 2 : 1; // Yes biasable, advance is slot 1 if( !(split instanceof MachNode mach) ) return 0; // Not biasable return mach.twoAddress(); // Only biasable if 2-addr } @@ -508,7 +532,7 @@ private static short biasColorNeighbors( RegAlloc alloc, Node split, RegMask mas // Can I limit my own choices to valid neighbor choices? for( LRG alrg : slrg._adj ) { - int reg = alrg._reg; + short reg = alrg._reg; if( reg == -1 && alrg._mask.size1() ) reg = alrg._mask.firstReg(); if( reg != -1 ) { diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/LRG.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/LRG.java index 0662c5f..79b2ad7 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/LRG.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/LRG.java @@ -61,6 +61,8 @@ public class LRG { // Adjacent Live Range neighbors. Only valid during coloring Ary _adj; + public int nadj() { return _adj==null ? 0 : _adj._len; } + void addNeighbor(LRG lrg) { if( _adj==null ) _adj = new Ary<>(LRG.class); _adj.push(lrg); @@ -79,7 +81,7 @@ void reinsert( LRG lrg ) { } // More registers than neighbors - boolean lowDegree() { return (_adj==null ? 0 : _adj._len) < _mask.size(); } + boolean lowDegree() { return nadj() < _mask.size(); } LRG( short lrg ) { _lrg = lrg; _reg = -1; } @@ -134,6 +136,7 @@ else if( _machDef==lrg._machDef ) if( _machUse==null ) { _machUse = lrg._machUse; + _uidx = lrg._uidx; } else if( lrg._machUse!=null ) { if( _machUse != lrg._machUse ) _multiUse=true; if( _1regUseCnt==0 ) { diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/LinkMem.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/LinkMem.java new file mode 100644 index 0000000..39f3dcb --- /dev/null +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/LinkMem.java @@ -0,0 +1,15 @@ +package com.compilerprogramming.ezlang.compiler.codegen; + +// In-memory linking +public class LinkMem { + final CodeGen _code; + LinkMem( CodeGen code ) { _code = code; } + + public CodeGen link() { + // Write any large constants into a constant pool; they + // are accessed by RIP-relative addressing. + _code._encoding.writeConstantPool(_code._encoding._bits,true); + + return _code; + } +} 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 273ac75..73acfd1 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 @@ -16,7 +16,7 @@ abstract public class Machine { // Return a MachNode unconditional branch public abstract CFGNode jump(); // Break an infinite loop - public abstract IfNode never( CFGNode ctrl ); + public abstract NeverNode never( CFGNode ctrl ); // Instruction select from ideal nodes public abstract Node instSelect( Node n ); 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 634ebf1..09d6c6b 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 @@ -150,7 +150,6 @@ public void regAlloc() { if( bb instanceof CallNode ) lastFun._hasCalls = true; } - // Top driver: repeated rounds of coloring and splitting. byte round=0; while( !graphColor(round) ) { @@ -202,11 +201,15 @@ void split(byte round) { // independently... which generally requires a full pass over the // program for each failing live range. i.e., might be a lot of // passes. - for( LRG lrg : _failed.keySet() ) + + // Sort, to avoid non-deterministic HashMap ordering + LRG[] splits = _failed.keySet().toArray(new LRG[0]); + Arrays.sort(splits, (x,y) -> x._lrg - y._lrg ); + for( LRG lrg : splits ) split(round,lrg); } - // Split this live range + // Split this live range, top level heuristic boolean split( byte round, LRG lrg ) { assert lrg.leader(); // Already rolled up @@ -220,8 +223,11 @@ boolean split( byte round, LRG lrg ) { lrg._1regUseCnt <= 1 && (lrg._1regDefCnt + lrg._1regUseCnt) > 0 ) return splitEmptyMaskSimple(round,lrg); - // Default to splitByLoop - //return splitEmptyMask(round,lrg); + // Repeated single-reg uses from a single def. Special for archs + // with more fixed regs. + if( !lrg._multiDef && lrg._1regDefCnt <= 1 && lrg._1regUseCnt > 2 ) + if( splitEmptyMaskByUse(round,lrg) ) + return true; } // Generic split-by-loop depth. @@ -244,39 +250,70 @@ boolean splitEmptyMaskSimple( byte round, LRG lrg ) { // alloc // V2/rax - kills prior RAX // st4 [V1],len - No good, must split around - makeSplit("def/empty1",round,lrg).insertAfter((Node)lrg._machDef, false/*true*/); + insertAfterAndReplace( makeSplit("def/empty1",round,lrg), (Node)lrg._machDef, false/*true*/); // Split just before use if( lrg._1regUseCnt==1 || (lrg._1regDefCnt==1 && ((Node)lrg._machDef).nOuts()==1) ) - insertBefore((Node)lrg._machUse,lrg._uidx,"use/empty1",round,lrg,true); + insertBefore((Node)lrg._machUse,lrg._uidx,"use/empty1",round,lrg); return true; } - // Split live range with an empty mask. Specifically forces splits at - // single-register defs or uses everywhere. - boolean splitEmptyMask( byte round, LRG lrg ) { - findAllLRG(lrg); - // If no single-use or single-def, assume this is a complete register - // kill and force spilling everywhere. - boolean all = lrg._killed || (lrg._1regDefCnt + lrg._1regUseCnt)==0; - for( Node n : _ns ) { - if( !(n instanceof MachNode mach) ) continue; - // Find def of spilling live range; spilling everywhere, OR - // single-register DEF and not cloneable (since these will clone - // before every use) - if( lrg(n)==lrg && (all || (!mach.isClone() && mach.outregmap().size1() )) ) - makeSplit(n,"def/empty2",round,lrg).insertAfter(n,true); - // Find all uses - for( int i=1; i rclass = new Ary<>(RegMask.class); + boolean done=false; + while( !done ) { + done = true; + for( Node use : def._outputs ) + if( use instanceof MachNode mach ) + for( int i=1; i1 ) split.setDef(1,def); + // all uses by class to split + 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 && mach.regmap( i ).overlap( rmask ) ) + // Modify use to use the split version specialized to this rclass + { use.setDef( i, split ); j--; break; } + } + } + } + return true; + } + + + // Put use into a register class, perhaps adding a class or perhaps + // narrowing a class (and causing a repeat) + private static boolean putIntoRegClass( Ary rclass, RegMask rmask ) { + for( int i=0; i loop.idepth() ) ) || (use instanceof MachNode mach && mach.twoAddress()!=0 && use.in(mach.twoAddress())==def) ) insertBefore( use, use._inputs.find(def), "use/self/use",round,lrg ); } @@ -303,9 +341,9 @@ boolean splitSelfConflict( byte round, LRG lrg ) { // TODO: split before all inputs (except the last; at least 1 split here must be extra) if( def instanceof PhiNode phi && !(def instanceof ParmNode) ) { SplitNode split = makeSplit("def/self",round,lrg); - split.insertAfter(def,false); + insertAfterAndReplace(split,def,false); if( split.nOuts()==0 ) - split.kill(); + split.killOrdered(); insertBefore(phi,1,"use/self/phi",round,lrg); } // Split before two-address ops which extend the live range @@ -357,10 +395,10 @@ boolean splitByLoop( byte round, LRG lrg ) { (min==max || n.cfg0().loopDepth() <= min) ) { // Cloneable constants will be cloned at uses, not after def if( !(n instanceof MachNode mach && mach.isClone()) && - // Single user is already a split - !(n.nOuts()==1 && n.out(0) instanceof SplitNode) ) + // Single user is already a split adjacent + !(n.nOuts()==1 && n.out(0) instanceof SplitNode split && sameBlockNoClobber(split) ) ) // Split after def in min loop nest - makeSplit("def/loop",round,lrg).insertAfter(n,false); + insertAfterAndReplace( makeSplit("def/loop",round,lrg), n,true); } // PhiNodes check all CFG inputs @@ -371,22 +409,19 @@ boolean splitByLoop( byte round, LRG lrg ) { // splitting in inner loop or at loop border (min==max || phi.region().cfg(i).loopDepth() <= min) && // and not around the backedge of a loop (bad place to force a split, hard to remove) - !(phi.region() instanceof LoopNode && i==2) ) + !(phi.region() instanceof LoopNode && i==2 && (phi.in(i) instanceof PhiNode pp && pp.region()==phi.region())) ) // Split before phi-use in prior block insertBefore(phi,i, "use/loop/phi",round,lrg); } else { // Others check uses for( int i=1; i>32); int d = cfg.loopDepth(); + // if n will lower the min loop and is in the tail end of the loop + // header, splitting "around" the loop will not help. Treat n as being + // in the loop. + if( d < min ) { + if( cfg.uctrl() instanceof LoopNode loop && loop.entry()==cfg ) { + for( int i=cfg.nOuts()-2; i>=0; i-- ) { + Node out = cfg.out(i); + if( n==out ) + { d = loop.loopDepth(); break; } // Treat n as being "in the loop" + if( !((out instanceof MachNode mach && mach.isClone()) || out instanceof SplitNode ) ) + break; // Treat b as "normal", out of loop + } + } + } + + // lower min, raise max, and re-fold min = Math.min(min,d); max = Math.max(max,d); return ((long)max<<32) | min; @@ -453,6 +504,24 @@ void insertBefore(Node n, int i, String kind, byte round, LRG lrg) { insertBefore(n,i,kind,round,lrg,true); } + // Replace uses of `def` with `split`, and insert `split` immediately after + // `def` in the basic block. + public void insertAfterAndReplace( Node split, Node def, boolean must ) { + split.insertAfter(def); + if( split.nIns()>1 ) split.setDef(1,def); + for( int j=def.nOuts()-1; j>=0; j-- ) { + Node use = def.out(j); + if( use==split ) continue; // Skip self + // Can we avoid a split of a split? 'this' split is used by + // another split in the same block. + if( !must && use instanceof SplitNode split2 && sameBlockNoClobber(split2) ) + continue; + int idx = use._inputs.find(def); + use.setDefOrdered(idx,split); + if( j < def.nOuts() ) j++; + } + } + private Node makeSplit( Node def, String kind, byte round, LRG lrg ) { Node split = def instanceof MachNode mach && mach.isClone() ? mach.copy() @@ -523,4 +592,24 @@ private boolean splitBypass( CFGNode bb, int j, Node lo, int defreg ) { lo.setDefOrdered(1,hi.in(1)); return true; } + + + public boolean sameBlockNoClobber( SplitNode split ) { + Node def = split.in(1); + CFGNode cfg = def.cfg0(); + if( cfg != split.cfg0() ) return false; // Not same block + // Get multinode head + Node def0 = def instanceof ProjNode ? def.in(0) : def; + int defreg = lrg(def)._reg; + if( defreg == -1 ) defreg = lrg(def)._mask.firstReg(); + if( defreg == -1 ) return false; // no allowed registers -> clobbered + for( int idx = cfg._outputs.find(split) -1; idx >= 0; idx-- ) { + Node n = cfg.out(idx); + if( n==def0 ) return true; // No clobbers + if( lrg(n) == lrg(def) ) return false; // Self conflict + if( lrg(n)!=null && lrg(n)._reg == defreg ) + return false; // Clobbered + } + throw Utils.TODO(); + } } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/RegMask.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/RegMask.java index a566187..e09c801 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/RegMask.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/RegMask.java @@ -32,6 +32,7 @@ public RegMask(int bit) { } public RegMask(long bits ) { _bits0 = bits; } public RegMask(long bits0, long bits1 ) { _bits0 = bits0; _bits1 = bits1; } + public RegMask(RegMask r) { _bits0 = r._bits0; _bits1 = r._bits1; } private RegMask() { _bits0 = _bits1 = 0; } // AND, with copy-on-write if changing @@ -65,6 +66,7 @@ public boolean clr( int reg ) { public short firstReg() { + if( isEmpty() ) return -1; return (short)(_bits0 != 0 ? Long.numberOfTrailingZeros(_bits0) : Long.numberOfTrailingZeros(_bits1)+64); @@ -118,25 +120,3 @@ public SB toString(SB sb) { } } -// Mutable regmask(writable) -class RegMaskRW extends RegMask { - public RegMaskRW(long x, long y) { super(x,y); } - // clears bit at position r. Returns true if the mask is still not empty. - public boolean clr(int r) { - if( r < 64 ) _bits0 &= ~(1L<<(r )); - else _bits1 &= ~(1L<<(r-64)); - return _bits0!=0 || _bits1!=0; - } - @Override RegMaskRW and( RegMask mask ) { - if( mask==null ) return this; - _bits0 &= mask._bits0; - _bits1 &= mask._bits1; - return this; - } - @Override RegMaskRW sub( RegMask mask ) { - if( mask==null ) return this; - _bits0 &= ~mask._bits0; - _bits1 &= ~mask._bits1; - return this; - } -} diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/RegMaskRW.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/RegMaskRW.java new file mode 100644 index 0000000..f391fcc --- /dev/null +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/RegMaskRW.java @@ -0,0 +1,31 @@ +package com.compilerprogramming.ezlang.compiler.codegen; + +// Mutable regmask(writable) +public class RegMaskRW extends RegMask { + public RegMaskRW(long x, long y) { super(x,y); } + // clears bit at position r. Returns true if the mask is still not empty. + public boolean clr(int r) { + if( r < 64 ) _bits0 &= ~(1L<<(r )); + else _bits1 &= ~(1L<<(r-64)); + return _bits0!=0 || _bits1!=0; + } + @Override RegMaskRW and( RegMask mask ) { + if( mask==null ) return this; + _bits0 &= mask._bits0; + _bits1 &= mask._bits1; + return this; + } + @Override RegMaskRW sub( RegMask mask ) { + if( mask==null ) return this; + _bits0 &= ~mask._bits0; + _bits1 &= ~mask._bits1; + return this; + } + public RegMaskRW or( RegMask mask ) { + if( mask!=null ) { + _bits0 |= mask._bits0; + _bits1 |= mask._bits1; + } + return this; + } +} diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/BoolNode.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/BoolNode.java index 9c9b744..8863de8 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/BoolNode.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/BoolNode.java @@ -91,6 +91,19 @@ SONTypeInteger doOp(SONTypeInteger i1, SONTypeInteger i2) { Node copy(Node lhs, Node rhs) { return new EQ(lhs,rhs); } Node copyF() { return new EQF(null,null); } } + + 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) { + if( i1==i2 && i1.isConstant() ) return TRUE; + if( i1._max < i2._min || i1._min > i2._max ) return FALSE; + return BOOL; + } + Node copy(Node lhs, Node rhs) { return new NE(lhs,rhs); } + Node copyF() { throw Utils.TODO(); } + } + public static class LT extends BoolNode { public LT(Node lhs, Node rhs) { super(lhs,rhs); } public String op() { return "<" ; } 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 3876fd2..2c348b7 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 @@ -51,6 +51,13 @@ public CFGNode uctrl() { return c; } + // Used by the encoding / final BB layout + public CFGNode uctrlSkipEmpty() { + CFGNode x = this, y=null; + while( x.nOuts() == 1 && (y=x.uctrl())!=null ) // Skip empty blocks + x = y; + return x; + } // ------------------------------------------------------------------------ /** @@ -97,7 +104,7 @@ public FunNode fun() { LoopTree _ltree; public int _pre; // Pre-order numbers for loop tree finding - private static class LoopTree { + static class LoopTree { LoopTree _par; final LoopNode _head; int _depth; diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/CallNode.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/CallNode.java index 52b3bf1..56902cf 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/CallNode.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/CallNode.java @@ -48,9 +48,11 @@ public String name() { public Node fptr() { return _inputs.last(); } // Error if not a TFP public SONTypeFunPtr tfp() { return (SONTypeFunPtr)fptr()._type; } + // Call is to an externally supplied code public boolean external() { return false; } + // Find the Call End from the Call public CallEndNode cend() { // Always in use slot 0 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 e858248..8ad7f3f 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 @@ -47,7 +47,7 @@ public StringBuilder _print1(StringBuilder sb, BitSet visited) { if( fun._name != null ) return sb.append("{ ").append(fun._name).append("}"); } - return sb.append(_con.print(new SB())); + return sb.append(_con==null ? "---" : _con.print(new SB())); } @Override public boolean isConst() { return true; } @@ -59,7 +59,7 @@ public StringBuilder _print1(StringBuilder sb, BitSet visited) { public Node idealize() { return null; } @Override - boolean eq(Node n) { + public boolean eq(Node n) { ConstantNode con = (ConstantNode)n; // Contract return _con==con._con; } 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 a48814f..3b4a282 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 @@ -32,6 +32,6 @@ public class FRefNode extends ConstantNode { public CompilerException err() { return Compiler.error("Undefined name '"+_n._name+"'"); } - @Override boolean eq(Node n) { return this==n; } + @Override public boolean eq(Node n) { return this==n; } @Override int hash() { return _n._idx; } } 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 5a5145c..b9475bd 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 @@ -68,6 +68,7 @@ public Node idealize() { // The following CProjs will be inverted by the caller. public void invert() { throw Utils.TODO(); } + // Negate the sense of a test public static String invert( String bop ) { return switch( bop ) { case "<" -> ">="; @@ -79,4 +80,17 @@ public static String invert( String bop ) { default -> throw Utils.TODO(); }; } + + // Swap compare operands + public static String swap( String bop ) { + return switch( bop ) { + case "<" -> ">" ; + case "<=" -> ">="; + case "==" -> "!="; + case "!=" -> "=="; + case ">" -> "<" ; + case ">=" -> "<="; + default -> throw Utils.TODO(); + }; + } } 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 721926c..e3f63f3 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,5 +1,6 @@ package com.compilerprogramming.ezlang.compiler.nodes; +import com.compilerprogramming.ezlang.compiler.codegen.CodeGen; import com.compilerprogramming.ezlang.compiler.sontypes.SONType; public class LoopNode extends RegionNode { @@ -33,41 +34,43 @@ public StopNode forceExit( FunNode fun, StopNode stop ) { while( x != this ) { if( x instanceof CProjNode exit && exit.in(0) instanceof IfNode iff ) { CFGNode other = iff.cproj(1-exit._idx); - if( other!=null && other.loopDepth() < loopDepth() ) + if( other!=null && other._ltree != _ltree && nested(_ltree,other._ltree) ) return stop; // Found an exit, not an infinite loop } x = x.idom(); } // Found a no-exit loop. Insert an exit - NeverNode iff = new NeverNode(back()); - for( Node use : _outputs ) - if( use instanceof PhiNode ) - iff.addDef(use); + NeverNode iff = CodeGen.CODE._mach == null + ? new NeverNode(back()) // Ideal never-branch + : CodeGen.CODE._mach.never(back()); // Machine never-branch CProjNode t = new CProjNode(iff,0,"True" ).init(); CProjNode f = new CProjNode(iff,1,"False").init(); - setDef(2,f); + setDef(2,t); + iff._ltree = t._ltree = _ltree; + ReturnNode ret = fun.ret(); + f._ltree = ret._ltree; // 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(); - ReturnNode ret = fun.ret(); Node ctrl = ret.ctrl(), mem = ret.mem(), expr = ret.expr(); - if( ctrl._type != SONType.XCONTROL ) { + if( ctrl!=null && ctrl._type != SONType.XCONTROL ) { // Perfect aligned exit? if( !(ctrl instanceof RegionNode r && mem instanceof PhiNode pmem && pmem.region()==r && expr instanceof PhiNode prez && prez.region()==r ) ) { // Nope, insert an aligned exit layer - ctrl = new RegionNode(null,ctrl).init(); - mem = new PhiNode((RegionNode)ctrl,mem ).init(); - expr = new PhiNode((RegionNode)ctrl,expr).init(); + RegionNode r = new RegionNode((Node)null,ctrl).init(); + ctrl = r; r._ltree = _ltree; + mem = new PhiNode(r,mem ).init(); + expr = new PhiNode(r,expr).init(); } // Append new Never exit - ctrl.addDef(t ); + ctrl.addDef(f ); mem .addDef(top); expr.addDef(top); } else { - ctrl = t; + ctrl = f; mem = top; expr = top; } @@ -77,4 +80,12 @@ public StopNode forceExit( FunNode fun, StopNode stop ) { return stop; } + + private static boolean nested(LoopTree inner, LoopTree outer) { + for( ; inner!=null; inner = inner._par ) + if( inner == outer ) + return true; + return false; + } + } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/MemOpNode.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/MemOpNode.java index ae96bed..1806b27 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/MemOpNode.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/MemOpNode.java @@ -44,7 +44,7 @@ public MemOpNode( Node mach, MemOpNode mop ) { } // - static String mlabel(String name) { return name.equals("[]") ? "ary" : (name.equals("#") ? "len" : name); } + static String mlabel(String name) { return "[]".equals(name) ? "ary" : ("#".equals(name) ? "len" : name); } String mlabel() { return mlabel(_name); } public Node mem() { return in(1); } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/Node.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/Node.java index 7d4c936..6975943 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/Node.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/Node.java @@ -227,6 +227,7 @@ public Node addDef(Node new_def) { } // Breaks the edge invariants, used temporarily + @SuppressWarnings("unchecked") protected N addUse(Node n) { _outputs.add(n); return (N)this; } // Remove node 'use' from 'def's (i.e. our) output list, by compressing the list in-place. @@ -268,6 +269,15 @@ public void kill( ) { assert isDead(); // Really dead now } + // Preserve CFG use-ordering when killing + public void killOrdered() { + CFGNode cfg = cfg0(); + cfg._outputs.remove(cfg._outputs.find(this)); + _inputs.set(0,null); + kill(); + } + + // Mostly used for asserts and printing. public boolean isDead() { return isUnused() && nIns()==0 && _type==null; } @@ -275,6 +285,7 @@ public void kill( ) { // Add bogus null use to keep node alive public N keep() { return addUse(null); } // Remove bogus null. + @SuppressWarnings("unchecked") public N unkeep() { delUse(null); return (N)this; @@ -301,9 +312,8 @@ public void subsume( Node nnn ) { kill(); } - // Replace uses of `def` with `this`, and insert `this` immediately after - // `def` in the basic block. - public void insertAfter( Node def, boolean must ) { + // insert `this` immediately after `def` in the same basic block. + public void insertAfter( Node def ) { CFGNode cfg = def.cfg0(); int i = cfg._outputs.find(def)+1; if( cfg instanceof CallEndNode ) { @@ -316,19 +326,6 @@ public void insertAfter( Node def, boolean must ) { while( cfg.out(i) instanceof PhiNode || cfg.out(i) instanceof CalleeSaveNode ) i++; cfg._outputs.insert(this,i); _inputs.set(0,cfg); - for( int j=def.nOuts()-1; j>=0; j-- ) { - // Can we avoid a split of a split? 'this' split is used by - // another split in the same block. - if( !must && def.out(j) instanceof SplitNode split && def.out(j).cfg0()==cfg && - !split._kind.contains("self") ) - continue; - Node use = def._outputs.del(j); - use.unlock(); - int idx = use._inputs.find(def); - use._inputs.set(idx,this); - addUse(use); - } - if( nIns()>1 ) setDef(1,def); } // Insert this in front of use.in(uidx) with this, and insert this @@ -338,6 +335,8 @@ public void insertBefore( Node use, int uidx ) { int i; if( use instanceof PhiNode phi ) { cfg = phi.region().cfg(uidx); + if( cfg instanceof CProjNode && cfg.in(0) instanceof NeverNode nvr ) + cfg = nvr.cfg0(); i = cfg.nOuts()-1; } else { i = cfg._outputs.find(use); @@ -349,7 +348,7 @@ public void insertBefore( Node use, int uidx ) { use.setDefOrdered(uidx,this); } - public void setDefOrdered(int idx, Node def) { + public void setDefOrdered( int idx, Node def) { // If old is dying, remove from CFG ordered Node old = in(idx); if( old!=null && old.nOuts()==1 ) { @@ -488,6 +487,7 @@ public SONType setType(SONType type) { return old; } + @SuppressWarnings("unchecked") public N init() { _type = compute(); return (N)this; } /** diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/AddARM.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/AddARM.java index d3ad62d..9fc20ac 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/AddARM.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/AddARM.java @@ -11,7 +11,7 @@ public class AddARM extends MachConcreteNode implements MachNode { @Override public RegMask outregmap() { return arm.RMASK; } // ADD (shifted register) - @Override public void encoding( Encoding enc ) { arm.r_reg(enc,this,0b10001011); } + @Override public void encoding( Encoding enc ) { arm.r_reg(enc,this,arm.OP_ADD); } // General form: "rd = rs1 + rs2" @Override public void asm(CodeGen code, SB sb) { sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" + ").p(code.reg(in(2))); diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/AddFARM.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/AddFARM.java index 7517d8f..807c0a4 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/AddFARM.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/AddFARM.java @@ -11,7 +11,7 @@ public class AddFARM extends MachConcreteNode implements MachNode { @Override public RegMask outregmap() { return arm.DMASK; } //FADD (scalar) - @Override public void encoding( Encoding enc ) { arm.f_scalar(enc,this,0b00011110); } + @Override public void encoding( Encoding enc ) { arm.f_scalar(enc,this,arm.OPF_ADD); } // Default on double precision for now(64 bits) // General form: "addf rd = src1 + src2 diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/AddIARM.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/AddIARM.java index ef16d9f..4c2b94a 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/AddIARM.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/AddIARM.java @@ -18,7 +18,7 @@ public class AddIARM extends MachConcreteNode implements MachNode { @Override public RegMask outregmap() { return arm.RMASK; } //ADD (immediate) @Override public void encoding( Encoding enc ) { - arm.imm_inst(enc,this,0b1001000100,_imm); + arm.imm_inst(enc,this, in(1), arm.OPI_ADD,_imm); } // General form: "addi rd = rs1 + imm" @Override public void asm(CodeGen code, SB sb) { diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/AndARM.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/AndARM.java index 903a307..94ee434 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/AndARM.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/AndARM.java @@ -13,7 +13,7 @@ public class AndARM extends MachConcreteNode implements MachNode { @Override public RegMask regmap(int i) { return arm.RMASK; } @Override public RegMask outregmap() { return arm.RMASK; } // AND (shifted register) - @Override public void encoding( Encoding enc ) { arm.r_reg(enc,this,0b10001010); } + @Override public void encoding( Encoding enc ) { arm.r_reg(enc,this,arm.OP_AND); } // General form: #rd = rs1 & rs2 @Override public void asm(CodeGen code, SB sb){ sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" & ").p(code.reg(in(2))); diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/AndIARM.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/AndIARM.java index 2412999..96b4485 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/AndIARM.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/AndIARM.java @@ -15,7 +15,7 @@ public class AndIARM extends MachConcreteNode implements MachNode { @Override public RegMask regmap(int i) { return arm.RMASK; } @Override public RegMask outregmap() { return arm.RMASK; } @Override public void encoding( Encoding enc ) { - arm.imm_inst_n(enc,this,0b100100100,_imm); + arm.imm_inst_n(enc,this, in(1), arm.OPI_AND,_imm); } // General form: "andi rd = rs1 & imm" @Override public void asm(CodeGen code, SB sb) { diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/AsrARM.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/AsrARM.java index 4711932..7bd9418 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/AsrARM.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/AsrARM.java @@ -10,7 +10,7 @@ public class AsrARM extends MachConcreteNode implements MachNode { @Override public String op() { return "sar"; } @Override public RegMask regmap(int i) { return arm.RMASK; } @Override public RegMask outregmap() { return arm.RMASK; } - @Override public void encoding( Encoding enc ) { arm.shift_reg(enc,this,0b1010); } + @Override public void encoding( Encoding enc ) { arm.shift_reg(enc,this,arm.OP_ASR); } @Override public void asm(CodeGen code, SB sb) { sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" >> ").p(code.reg(in(2))); } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/AsrIARM.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/AsrIARM.java index 05a508c..3f903b3 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/AsrIARM.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/AsrIARM.java @@ -22,7 +22,7 @@ public class AsrIARM extends MachConcreteNode implements MachNode { short rd = enc.reg(this); short rn = enc.reg(in(1)); assert _imm > 0; - enc.add4(arm.imm_shift(0b1001001101,_imm, 0b111111, rn, rd)); + enc.add4(arm.imm_shift(arm.OPI_ASR,_imm, 0b111111, rn, rd)); } // General form: "asri rd = rs1 >> imm" @Override public void asm(CodeGen code, SB sb) { diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/BranchARM.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/BranchARM.java index 12ce1c2..8494f39 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/BranchARM.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/BranchARM.java @@ -28,13 +28,12 @@ public class BranchARM extends IfNode implements MachNode, RIPRelSize { @Override public RegMask outregmap() { return null; } @Override public void invert() { _bop = invert(_bop); } - // Encoding is appended into the byte array; size is returned @Override public void encoding( Encoding enc ) { // Assuming that condition flags are already set. These flags are set // by comparison (or sub). No need for regs because it uses flags enc.jump(this,cproj(0)); // B.cond - enc.add4( arm.b_cond(0b01010100, 0, arm.make_condition(_bop)) ); + enc.add4( arm.b_cond(arm.OP_BRANCH, 0, arm.make_condition(_bop)) ); } // Delta is from opcode start @@ -47,7 +46,7 @@ public class BranchARM extends IfNode implements MachNode, RIPRelSize { // Delta is from opcode start @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { if( opLen==4 ) { - enc.patch4(opStart,arm.b_cond(0b01010100, delta, arm.make_condition(_bop))); + enc.patch4(opStart,arm.b_cond(arm.OP_BRANCH, delta, arm.make_condition(_bop))); } else { throw Utils.TODO(); } @@ -56,9 +55,8 @@ public class BranchARM extends IfNode implements MachNode, RIPRelSize { @Override public void asm(CodeGen code, SB sb) { String src = code.reg(in(1)); if( src!="flags" ) sb.p(src).p(" "); - CFGNode prj = cproj(0); - while( prj.nOuts() == 1 ) - prj = prj.uctrl(); // Skip empty blocks + CFGNode prj = cproj(0).uctrlSkipEmpty(); + if( !prj.blockHead() ) prj = prj.cfg0(); sb.p(label(prj)); } @Override public String comment() { return "L"+cproj(1)._nid; } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/CallARM.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/CallARM.java index d16a25f..94722aa 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/CallARM.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/CallARM.java @@ -27,7 +27,7 @@ public class CallARM extends CallNode implements MachNode, RIPRelSize { @Override public void encoding( Encoding enc ) { enc.relo(this); // BL - enc.add4(arm.b(0b100101,0)); // Target patched at link time + enc.add4(arm.b(arm.OP_CALL,0)); // Target patched at link time } // Delta is from opcode start, but X86 measures from the end of the 5-byte encoding @@ -35,7 +35,7 @@ public class CallARM extends CallNode implements MachNode, RIPRelSize { // Delta is from opcode start @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { - enc.patch4(opStart,arm.b(0b100101,delta)); + enc.patch4(opStart,arm.b(arm.OP_CALL,delta)); } @Override public void asm(CodeGen code, SB sb) { diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/CallRRARM.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/CallRRARM.java index a8cb51b..71f9382 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/CallRRARM.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/CallRRARM.java @@ -19,7 +19,7 @@ public class CallRRARM extends CallNode implements MachNode { // Needs a register, typically a jump-and-link-register opcode // blr short self = enc.reg(this); - enc.add4(arm.blr(0b1101011000111111000000, self)); + enc.add4(arm.blr(arm.OP_CALLRARM, self)); } @Override public void asm(CodeGen code, SB sb) { diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/CmpARM.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/CmpARM.java index 5e2366b..b5dba20 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/CmpARM.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/CmpARM.java @@ -11,7 +11,7 @@ public class CmpARM extends MachConcreteNode implements MachNode { @Override public RegMask outregmap() { return arm.FLAGS_MASK; } // SUBS (shifted register) - @Override public void encoding( Encoding enc ) { arm.r_reg(enc,this,0b11101011); } + @Override public void encoding( Encoding enc ) { arm.r_reg(enc,this,arm.OP_CMP); } // General form: "cmp rs1, rs2" @Override public void asm(CodeGen code, SB sb) { diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/CmpIARM.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/CmpIARM.java index af1fccc..c9b85f4 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/CmpIARM.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/CmpIARM.java @@ -5,7 +5,7 @@ import com.compilerprogramming.ezlang.compiler.nodes.*; // Compare with immediate. -// Conditional compare (immediate)? e.g CCMP(immediate) +// CMP (immediate) - SUBS public class CmpIARM extends MachConcreteNode implements MachNode { final int _imm; final String _bop; @@ -27,8 +27,8 @@ public class CmpIARM extends MachConcreteNode implements MachNode { @Override public RegMask outregmap() { return arm.FLAGS_MASK; } @Override public boolean isClone() { return true; } @Override public Node copy() { return new CmpIARM(this); } - // Encoding is appended into the byte array; size is returned - @Override public void encoding( Encoding enc ) { arm.imm_inst(enc,this,964,_imm); } + + @Override public void encoding( Encoding enc ) { arm.imm_inst(enc,in(1),in(1), arm.OPI_CMP,_imm); } // General form: "cmp rs1, 1" @Override public void asm(CodeGen code, SB sb) { diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/DivARM.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/DivARM.java index 16deea1..e9c8dbc 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/DivARM.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/DivARM.java @@ -10,7 +10,7 @@ public class DivARM extends MachConcreteNode implements MachNode { @Override public RegMask regmap(int i) { return arm.RMASK; } @Override public RegMask outregmap() { return arm.RMASK; } // SDIV - @Override public void encoding( Encoding enc ) { arm.madd(enc,this,0b10011010110,3); } + @Override public void encoding( Encoding enc ) { arm.madd(enc,this,arm.OP_DIV,3); } // General form: "div dst /= src" @Override public void asm(CodeGen code, SB sb) { sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" / ").p(code.reg(in(2))); diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/DivFARM.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/DivFARM.java index fa550cb..f86ccfd 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/DivFARM.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/DivFARM.java @@ -11,7 +11,7 @@ public class DivFARM extends MachConcreteNode implements MachNode { @Override public RegMask outregmap() { return arm.DMASK; } // FDIV (scalar) - @Override public void encoding( Encoding enc ) { arm.f_scalar(enc,this,0b000110); } + @Override public void encoding( Encoding enc ) { arm.f_scalar(enc,this,arm.OPF_DIV); } // General form: "VDIF = dst /= src" @Override public void asm(CodeGen code, SB sb) { sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" / ").p(code.reg(in(2))); diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/FloatARM.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/FloatARM.java index c56d88e..b8f41b1 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/FloatARM.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/FloatARM.java @@ -18,11 +18,11 @@ public class FloatARM extends ConstantNode implements MachNode, RIPRelSize { @Override public FloatARM copy() { return new FloatARM(this); } @Override public void encoding( Encoding enc ) { - enc.largeConstant(this,_con); + enc.largeConstant(this,_con,0,-1/*TODO: ARM-style ELF patching*/); short dst = (short)(enc.reg(this) - arm.D_OFFSET); double d = ((SONTypeFloat)_con).value(); long x = Double.doubleToRawLongBits(d); - enc.add4(arm.load_pc(0b01011100, 0, dst)); + enc.add4(arm.load_pc(arm.OPF_ARM, 0, dst)); } // Delta is from opcode start. @@ -31,7 +31,7 @@ public class FloatARM extends ConstantNode implements MachNode, RIPRelSize { // Delta is from opcode start @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { short dst = (short)(enc.reg(this) - arm.D_OFFSET); - enc.add4(arm.load_pc(0b01011100, delta, dst)); + enc.add4(arm.load_pc(arm.OPF_ARM, delta, dst)); } // Human-readable form appended to the SB. Things like the encoding, diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/FunARM.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/FunARM.java index 96fc6cc..a270595 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/FunARM.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/FunARM.java @@ -27,7 +27,7 @@ public class FunARM extends FunNode implements MachNode { _maxArgSlot = arm.maxSlot(enc._fun.sig()); _frameAdjust = (short) (_maxSlot+1 - _maxArgSlot); if( _frameAdjust == 0 ) return; // Skip if no frame adjust - enc.add4(arm.imm_inst(0b1001000100, (_frameAdjust*8)&0xFFF, arm.RSP, arm.RSP)); + enc.add4(arm.imm_inst(arm.OPI_ADD, (_frameAdjust*8)&0xFFF, arm.RSP, arm.RSP)); } @Override public void asm(CodeGen code, SB sb) { diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/I2F8ARM.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/I2F8ARM.java index ef24c5a..2793fbb 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/I2F8ARM.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/I2F8ARM.java @@ -13,7 +13,7 @@ public class I2F8ARM extends MachConcreteNode implements MachNode { // SCVTF short self = (short)(enc.reg(this )-arm.D_OFFSET); short reg1 = enc.reg(in(1)); - int body = arm.float_cast(0b10011110, 1, reg1, self); + int body = arm.float_cast(arm.OP_FLOAT_C, 1, reg1, self); enc.add4(body); } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/IntARM.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/IntARM.java index 2608b04..495559b 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/IntARM.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/IntARM.java @@ -33,11 +33,11 @@ public class IntARM extends ConstantNode implements MachNode { if(nb0 >= nb1) { // More 0 blocks then F blocks, use movz pattern = 0; - op = 0b110100101; + op = arm.OP_MOVZ; } else { // More F blocks then 0 blocks, use movn pattern = 0xFFFF; - op = 0b100100101; + op = arm.OP_MOVN; } int invert = pattern; for (int i=0; i<4; i++) { @@ -45,11 +45,11 @@ public class IntARM extends ConstantNode implements MachNode { x >>= 16; if (block != pattern) { enc.add4(arm.mov(op, i, block ^ invert, self)); - op = 0b111100101; + op = arm.OP_MOVK; invert = 0; } } - if (op != 0b111100101) { + if (op != arm.OP_MOVK) { // All blocks are the same, special case enc.add4(arm.mov(op, 0, 0, self)); } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/LoadARM.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/LoadARM.java index 6d11b2f..2700fdb 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/LoadARM.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/LoadARM.java @@ -21,9 +21,9 @@ public class LoadARM extends MemOpARM{ // ldr(immediate - unsigned offset) | ldr(register) @Override public void encoding( Encoding enc ) { if(_declaredType == SONTypeFloat.F32 || _declaredType == SONTypeFloat.F64) { - ldst_encode(enc, 0b1111110101, 0b11111100011, this, true); + ldst_encode(enc, arm.OPF_LOAD_IMM, arm.OPF_LOAD_R, this, true); } else { - ldst_encode(enc, 0b1111100101, 0b11111000011, this, false); + ldst_encode(enc, arm.OP_LOAD_IMM, arm.OP_LOAD_R, this, false); } } @Override public void asm(CodeGen code, SB sb) { diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/LslARM.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/LslARM.java index 0596fc2..594e0e4 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/LslARM.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/LslARM.java @@ -11,7 +11,7 @@ public class LslARM extends MachConcreteNode implements MachNode { @Override public RegMask regmap(int i) { return arm.RMASK; } @Override public RegMask outregmap() { return arm.RMASK; } - @Override public void encoding( Encoding enc ) { arm.shift_reg(enc,this,0b1000); } + @Override public void encoding( Encoding enc ) { arm.shift_reg(enc,this,arm.OP_LSL); } @Override public void asm(CodeGen code, SB sb) { sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" << ").p(code.reg(in(2))); } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/LslIARM.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/LslIARM.java index 9201580..a82fbf4 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/LslIARM.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/LslIARM.java @@ -24,7 +24,7 @@ public class LslIARM extends MachConcreteNode implements MachNode { assert _imm > 0; // UBFM , , #(- MOD 64), #(63-) // immr must be (- MOD 64) = 64 - shift - enc.add4(arm.imm_shift(0b1101001101, 64 - _imm, (64 - _imm) - 1, rn, rd)); + enc.add4(arm.imm_shift(arm.OPI_LSL, 64 - _imm, (64 - _imm) - 1, rn, rd)); } // General form: "lsli rd = rs1 << imm" @Override public void asm(CodeGen code, SB sb) { diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/LsrARM.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/LsrARM.java index afd84ba..af4763b 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/LsrARM.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/LsrARM.java @@ -11,7 +11,7 @@ public class LsrARM extends MachConcreteNode implements MachNode { @Override public RegMask regmap(int i) { return arm.RMASK; } @Override public RegMask outregmap() { return arm.RMASK; } - @Override public void encoding( Encoding enc ) { arm.shift_reg(enc,this,0b1001); } + @Override public void encoding( Encoding enc ) { arm.shift_reg(enc,this,arm.OP_LSR); } @Override public void asm(CodeGen code, SB sb) { sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" >>> ").p(code.reg(in(2))); } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/LsrIARM.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/LsrIARM.java index 72629ff..f1fff80 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/LsrIARM.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/LsrIARM.java @@ -20,7 +20,7 @@ public class LsrIARM extends MachConcreteNode implements MachNode { short rd = enc.reg(this); short rn = enc.reg(in(1)); assert _imm > 0; - enc.add4(arm.imm_shift(0b1101001101,_imm, 0b111111, rn,rd)); + enc.add4(arm.imm_shift(arm.OPI_LSR,_imm, 0b111111, rn,rd)); } // General form: "lsri rd = rs1 >>> imm" @Override public void asm(CodeGen code, SB sb) { diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/MulARM.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/MulARM.java index 776f507..1f69b83 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/MulARM.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/MulARM.java @@ -11,7 +11,7 @@ public class MulARM extends MachConcreteNode implements MachNode { @Override public RegMask regmap(int i) { return arm.RMASK; } @Override public RegMask outregmap() { return arm.RMASK; } - @Override public void encoding( Encoding enc ) { arm.madd(enc,this,0b10011011000,31); } + @Override public void encoding( Encoding enc ) { arm.madd(enc,this,arm.OP_MUL,31); } // General form: "rd = rs1 * rs2" @Override public void asm(CodeGen code, SB sb) { sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" * ").p(code.reg(in(2))); diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/MulFARM.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/MulFARM.java index 3143d6e..1464fc9 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/MulFARM.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/MulFARM.java @@ -9,7 +9,7 @@ public class MulFARM extends MachConcreteNode implements MachNode{ @Override public String op() { return "mulf"; } @Override public RegMask regmap(int i) { return arm.DMASK; } @Override public RegMask outregmap() { return arm.DMASK; } - @Override public void encoding( Encoding enc ) { arm.f_scalar(enc,this,0b10); } + @Override public void encoding( Encoding enc ) { arm.f_scalar(enc,this,arm.OPF_MUL); } // Default on double precision for now(64 bits) // General form: "VMUL.f32 rd = src1 * src2 @Override public void asm(CodeGen code, SB sb) { diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/NewARM.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/NewARM.java index 76a1424..e867fed 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/NewARM.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/NewARM.java @@ -15,7 +15,7 @@ public class NewARM extends NewNode implements MachNode { @Override public void encoding( Encoding enc ) { // bl - enc.external(this,"calloc").add4(arm.b(0b100101, 0)); + enc.external(this,"calloc").add4(arm.b(arm.OP_CALL, 0)); } @Override public void asm(CodeGen code, SB sb) { diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/NotARM.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/NotARM.java index 97537eb..19d0408 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/NotARM.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/NotARM.java @@ -18,9 +18,9 @@ public class NotARM extends MachConcreteNode implements MachNode{ // subtracting zero from rs will just yield rs, it sets the zero flag and then it's used in cset short self = enc.reg(this ); short reg1 = enc.reg(in(1)); - int subs = arm.imm_inst(0b1111000100, 0, reg1, self); + int subs = arm.imm_inst(arm.OP_SUBS, 0, reg1, self); enc.add4(subs); - int cset = arm.cond_set(0b10011010100, 31, arm.COND.EQ, 63, reg1); + int cset = arm.cond_set(arm.OP_CSET, 31, arm.COND.EQ, 63, reg1); enc.add4(cset); } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/OrARM.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/OrARM.java index 5b07950..7208ea9 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/OrARM.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/OrARM.java @@ -11,7 +11,7 @@ public class OrARM extends MachConcreteNode implements MachNode { @Override public String glabel() { return "|"; } @Override public RegMask regmap(int i) { return arm.RMASK; } @Override public RegMask outregmap() { return arm.RMASK; } - @Override public void encoding( Encoding enc ) { arm.r_reg(enc,this,0b10101010); } + @Override public void encoding( Encoding enc ) { arm.r_reg(enc,this,arm.OP_OR); } // General form: #rd = rs1 & rs2 @Override public void asm(CodeGen code, SB sb) { sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" | ").p(code.reg(in(2))); diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/OrIARM.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/OrIARM.java index 7773166..c33de85 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/OrIARM.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/OrIARM.java @@ -15,7 +15,7 @@ public class OrIARM extends MachConcreteNode implements MachNode { @Override public RegMask regmap(int i) { return arm.RMASK; } @Override public RegMask outregmap() { return arm.RMASK; } @Override public void encoding( Encoding enc ) { - arm.imm_inst_n(enc, this, 0b101100100, _imm); + arm.imm_inst_n(enc, this, in(1), arm.OPI_OR, _imm); } // General form: "ori rd = rs1 | imm" @Override public void asm(CodeGen code, SB sb) { diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/RetARM.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/RetARM.java index 1250365..7497cb4 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/RetARM.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/RetARM.java @@ -21,8 +21,8 @@ public class RetARM extends ReturnNode implements MachNode { @Override public void encoding( Encoding enc ) { int frameAdjust = ((FunARM)fun())._frameAdjust; if( frameAdjust > 0 ) - enc.add4(arm.imm_inst(0b1001000100, (frameAdjust*-8)&0xFFF, arm.RSP, arm.RSP)); - enc.add4(arm.ret(0b1101011001011111000000)); + enc.add4(arm.imm_inst(arm.OPI_ADD, (frameAdjust*-8)&0xFFF, arm.RSP, arm.RSP)); + enc.add4(arm.ret(arm.OP_RET)); } @Override public void asm(CodeGen code, SB sb) { diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/SetARM.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/SetARM.java index c8b149d..d3806f9 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/SetARM.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/SetARM.java @@ -19,9 +19,8 @@ public class SetARM extends MachConcreteNode implements MachNode { @Override public RegMask regmap(int i) { assert i==1; return arm.FLAGS_MASK; } @Override public RegMask outregmap() { return arm.RMASK; } - // Encoding is appended into the byte array; size is returned @Override public void encoding( Encoding enc ) { - int body = arm.cset(0b1001101010011111, arm.make_condition(_bop), 0b0111111, enc.reg(this)); + int body = arm.cset(arm.OP_CSET,0b11111, arm.make_condition(_bop), 0b011111, enc.reg(this)); enc.add4(body); } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/SplitARM.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/SplitARM.java index 3498554..1686008 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/SplitARM.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/SplitARM.java @@ -24,31 +24,35 @@ public class SplitARM extends SplitNode { throw Utils.TODO(); } int off = enc._fun.computeStackSlot(dst - arm.MAX_REG)*8; - enc.add4(arm.load_str_imm(0b1111100100, off, src, dst)); + if( srcX ) src -= arm.D_OFFSET; + enc.add4(arm.load_str_imm(arm.OP_STORE_IMM, off, arm.RSP, src)); + return; } if(src >= arm.MAX_REG) { // Load from SP int off = enc._fun.computeStackSlot(src - arm.MAX_REG) * 8; - enc.add4(arm.load_str_imm(0b1111100101, off, src, dst)); + if( dstX ) dst -= arm.D_OFFSET; + enc.add4(arm.load_str_imm(arm.OP_LOAD_IMM, off, arm.RSP, dst)); + return; } // pick opcode based on regs if(!dstX && !srcX) { // GPR->GPR - enc.add4(arm.mov_reg(0b10101010000, src, dst)); + enc.add4(arm.mov_reg(arm.OP_MOV, src, dst)); } else if(dstX && srcX) { // FPR->FPR // fmov reg - enc.add4(arm.f_mov_reg(0b00011110, src,dst)); - } else if(dstX && !srcX) { + enc.add4(arm.f_mov_reg(arm.OP_FMOV_REG, src - arm.D_OFFSET,dst - arm.D_OFFSET)); + } else if(!srcX && dstX) { // GPR->FPR // FMOV(general) 64 bits to DOUBLE-PRECISION - enc.add4(arm.f_mov_general(0b10011110, 0b01, 0, 0b111, src, dst)); - } else if(!dstX && srcX) { + enc.add4(arm.f_mov_general(arm.OP_FMOV, 0b01, 0, 0b111, src, dst - arm.D_OFFSET)); + } else if( srcX && !dstX) { //FPF->GPR // FMOV(general) DOUBLE-PRECISION to 64 bits - enc.add4(arm.f_mov_general(0b10011110, 0b01, 0, 0b110, src, dst)); + enc.add4(arm.f_mov_general(arm.OP_FMOV, 0b01, 0, 0b110, src - arm.D_OFFSET, dst)); } } } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/StoreARM.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/StoreARM.java index 69fc9f1..2bab0ee 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/StoreARM.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/StoreARM.java @@ -24,9 +24,9 @@ public class StoreARM extends MemOpARM { @Override public RegMask outregmap() { return null; } @Override public void encoding( Encoding enc ) { if(_declaredType == SONTypeFloat.F32 || _declaredType == SONTypeFloat.F64) { - ldst_encode(enc, 0b1111110100,0b11111100001, val(), true); + ldst_encode(enc, arm.OPF_STORE_IMM,arm.OPF_STORE_R, val(), true); } else { - ldst_encode(enc, 0b1111100100, 0b11111000001, val(), false); + ldst_encode(enc, arm.OP_STORE_IMM, arm.OP_STORE_R, val(), false); } } @Override public void asm(CodeGen code, SB sb) { diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/SubARM.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/SubARM.java index 847a0b4..43e71fb 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/SubARM.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/SubARM.java @@ -10,7 +10,7 @@ public class SubARM extends MachConcreteNode implements MachNode { @Override public RegMask regmap(int i) { return arm.RMASK; } @Override public RegMask outregmap() { return arm.RMASK; } - @Override public void encoding( Encoding enc ) { arm.r_reg(enc,this,0b11001011); } + @Override public void encoding( Encoding enc ) { arm.r_reg(enc,this,arm.OP_SUB); } // General form: "sub # rd = rs1 - rs2" @Override public void asm(CodeGen code, SB sb) { diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/SubFARM.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/SubFARM.java index a1326f2..b43dbc4 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/SubFARM.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/SubFARM.java @@ -9,7 +9,7 @@ public class SubFARM extends MachConcreteNode implements MachNode { @Override public String op() { return "subf"; } @Override public RegMask regmap(int i) { return arm.DMASK; } @Override public RegMask outregmap() { return arm.DMASK; } - @Override public void encoding( Encoding enc ) { arm.f_scalar(enc,this,0b1110); } + @Override public void encoding( Encoding enc ) { arm.f_scalar(enc,this,arm.OPF_SUB); } // Default on double precision for now(64 bits) // General form: "vsub.f32 rd = src1 + src2 @Override public void asm(CodeGen code, SB sb) { diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/SubIARM.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/SubIARM.java index 2ada6af..b7ff3a9 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/SubIARM.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/SubIARM.java @@ -18,7 +18,7 @@ public class SubIARM extends MachConcreteNode implements MachNode { @Override public RegMask regmap(int i) { return arm.RMASK; } @Override public RegMask outregmap() { return arm.RMASK; } - @Override public void encoding( Encoding enc ) { arm.imm_inst(enc,this,0b1101000100,_imm); } + @Override public void encoding( Encoding enc ) { arm.imm_inst(enc,this, in(1), 0b1101000100,_imm); } // General form: "subi rd = rs1 - imm" @Override public void asm(CodeGen code, SB sb) { diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/TFPARM.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/TFPARM.java index 1be5a4e..757c809 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/TFPARM.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/TFPARM.java @@ -18,10 +18,10 @@ public class TFPARM extends ConstantNode implements MachNode, RIPRelSize { enc.relo(this); short self = enc.reg(this); // adrp x0, 0 - int adrp = arm.adrp(1,0, 0b10000, 0,self); + int adrp = arm.adrp(1,0, arm.OP_ADRP, 0,self); // add x0, x0, 0 - arm.imm_inst(enc,this,0b1001000100,0); enc.add4(adrp); + arm.imm_inst(enc,arm.OPI_ADD,0, 0); } @Override public byte encSize(int delta) { @@ -32,15 +32,16 @@ public class TFPARM extends ConstantNode 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 ) { + if(opLen == 8 ) { // opstart of add int next = opStart + opLen; int adrp_delta = delta >> 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(enc, this, 0b1001000100, delta & 0xfff)); + enc.patch4(next, 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(); } } 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 fa566b5..65e314f 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 @@ -20,7 +20,7 @@ public class UJmpARM extends CFGNode implements MachNode, RIPRelSize { @Override public Node idealize() { throw Utils.TODO(); } @Override public void encoding( Encoding enc ) { enc.jump(this,uctrl()); - int body = arm.b(0b01010100, 0); + int body = arm.b(arm.OP_UJMP, 0); enc.add4(body); } @@ -34,7 +34,7 @@ public class UJmpARM extends CFGNode implements MachNode, RIPRelSize { // Delta is from opcode start @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { if( opLen==4 ) { - enc.patch4(opStart,arm.b(0b01010100, delta)); + enc.patch4(opStart,arm.b(arm.OP_UJMP, delta)); } else { throw Utils.TODO(); } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/XorARM.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/XorARM.java index ac9e38b..0132936 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/XorARM.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/XorARM.java @@ -10,7 +10,7 @@ public class XorARM extends MachConcreteNode implements MachNode{ @Override public String glabel() { return "^"; } @Override public RegMask regmap(int i) { return arm.RMASK; } @Override public RegMask outregmap() { return arm.RMASK; } - @Override public void encoding( Encoding enc ) { arm.r_reg(enc,this,0b11001010); } + @Override public void encoding( Encoding enc ) { arm.r_reg(enc,this,arm.OP_XOR); } // General form: "rd = x1 ^ x2" @Override public void asm(CodeGen code, SB sb) { sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" ^ ").p(code.reg(in(2))); diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/XorIARM.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/XorIARM.java index 2dc314a..cb3a28d 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/XorIARM.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/XorIARM.java @@ -20,7 +20,7 @@ public class XorIARM extends MachConcreteNode implements MachNode { @Override public RegMask outregmap() { return arm.RMASK; } // General form: "xori rd = rs1 ^ imm" - @Override public void encoding( Encoding enc ) { arm.imm_inst_n(enc,this,0b110100100,_imm); } + @Override public void encoding( Encoding enc ) { arm.imm_inst_n(enc,this, in(1), arm.OPI_XOR,_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/arm/arm.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/arm/arm.java index 4f01b8d..34db62e 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 @@ -90,6 +90,79 @@ public arm( CodeGen code ) { static final RegMask D6_MASK = new RegMask(D6); static final RegMask D7_MASK = new RegMask(D7); + // major opcode: OP + public static int OP_ADD = 0b10_001_011; + public static int OPF_ADD = 0b00_011_110; + public static int OPI_ADD = 0b10_010_00100; + + public static int OP_UJMP = 0b01010100; + + public static int OP_ADRP = 0b10000; + + public static int OP_ASR = 0b1010; + public static int OPI_ASR = 0b10_0100_1101; + + public static int OP_LSL = 0b1000; + public static int OPI_LSL =0b1101001101; + + + public static int OP_LSR = 0b1001; + public static int OPI_LSR = 0b1101001101; + + public static int OP_BRANCH = 0b01_0101_00; + public static int OP_CALL = 0b10_010_1; + + public static int OP_CALLRARM = 0b1101011000111111000000; + + public static int OP_SUBS = 0b1111000100; + public static int OP_CSET = 0b10011010100; + public static int OP_CMP = 0b11101011; + public static int OPI_CMP = 0b1111000100; + + public static int OP_DIV = 0b10011010110; + public static int OPF_DIV = 0b000110; + + public static int OP_MUL = 0b10011011000; + public static int OPF_MUL = 0b10; + + public static int OPF_ARM = 0b01011100; + + public static int OP_FLOAT_C = 0b10011110; + + public static int OP_XOR = 0b11001010; + public static int OPI_XOR = 0b110100100; + + public static int OP_AND = 0b10_0010_10; + public static int OPI_AND = 0b10_0100_100; + + public static int OP_OR = 0b10101010; + public static int OPI_OR = 0b101100100; + + public static int OP_SUB = 0b11001011; + public static int OPF_SUB = 0b1110; + + public static int OP_MOVK = 0b111100101; + public static int OP_MOVN = 0b100100101; + public static int OP_MOVZ = 0b110100101; + + public static int OP_RET = 0b1101011001011111000000; + // Store/load opcodes + public static int OP_LOAD_R = 0b11111000011; + public static int OP_LOAD_IMM = 0b1111100101; + + public static int OPF_LOAD_R = 0b11111100011; + public static int OPF_LOAD_IMM = 0b1111110101; + + public static int OP_STORE_R = 0b11111000001; + public static int OP_STORE_IMM = 0b1111100100; + + public static int OPF_STORE_R = 0b11111100001; + public static int OPF_STORE_IMM = 0b1111110100; + + public static int OP_FMOV = 0b10011110; + public static int OP_FMOV_REG = 0b00011110; + // https://docsmirror.github.io/A64/2023-06/mov_orr_log_shift.html + public static int OP_MOV = 0b10101010000; // Calling convention; returns a machine-specific register // for incoming argument idx. // index 0 for control, 1 for memory, real args start at index 2 @@ -125,7 +198,16 @@ public enum OPTION { SXTX, } + static public int cset(int opcode, int rm, COND cond, int rn, int rd) { + assert 0 <= rm && rm < 32; + assert 0 <= rn && rn < 32; + assert 0 <= rd && rd < 32; + return (opcode << 21) | (rm << 15) | (cond.ordinal() << 12) | (rn << 5) | rd; + } + static public int cset(int opcode, COND cond, int rn, int rd) { + assert 0 <= rn && rn < 32; + assert 0 <= rd && rd < 32; return (opcode << 16) | (cond.ordinal() << 12) | (rn << 5) | rd; } @@ -210,24 +292,34 @@ private static int imm12Logical(SONTypeInteger ti) { // sh is encoded in opcdoe public static int imm_inst(int opcode, int imm12, int rn, int rd) { - assert opcode >=0 && imm12 >= 0 && rn >=0 && rd>=0; // Caller zeros high order bits + assert 0 <= rn && rn < 32; + assert 0 <= rd && rd < 32; + assert opcode >=0 && imm12 >= 0; // Caller zeros high order bits return (opcode << 22) | (imm12 << 10) | (rn << 5) | rd; } public static int imm_shift(int opcode, int imm, int imms, int rn, int rd) { - return (opcode << 22) | (1 << 22) | (imm << 16) | (imms << 10) | (rn << 5) | rd; + assert 0 <= rn && rn < 32; + assert 0 <= rd && rd < 32; + return (opcode << 22) | (1 << 22) | (imm << 16) | (imms << 10) | (rn << 5) | rd; } - public static void imm_inst(Encoding enc, Node n, int opcode, int imm12) { + public static void imm_inst(Encoding enc, Node n,Node n2, int opcode, int imm12) { short self = enc.reg(n); - short reg1 = enc.reg(n.in(1)); + short reg1 = enc.reg(n2); int body = imm_inst(opcode, imm12&0xFFF, reg1, self); enc.add4(body); } - public static void imm_inst_n(Encoding enc, Node n, int opcode, int imm13) { + // for cases where rs1 and dst are the same, eg add x0, x0, 1 + public static void imm_inst(Encoding enc, int opcode, int imm12, int self) { + int body = imm_inst(opcode, imm12&0xFFF, self, self); + enc.add4(body); + } + + public static void imm_inst_n(Encoding enc, Node n, Node n2, int opcode, int imm13) { short self = enc.reg(n); - short reg1 = enc.reg(n.in(1)); + short reg1 = enc.reg(n2); int body = imm_inst_n(opcode, imm13, reg1, self); enc.add4(body); @@ -235,10 +327,18 @@ public static void imm_inst_n(Encoding enc, Node n, int opcode, int imm13) { // nth bit comes from immediate and not opcode public static int imm_inst_n(int opcode, int imm13, int rn, int rd) { + assert 0 <= rn && rn < 32; + assert 0 <= rd && rd < 32; assert 0 <= imm13 && imm13 <= 0x1FFF; return (opcode << 23) | (imm13 << 10) | (rn << 5) | rd; } + public static int imm_inst_l(int opcode, int imm12, int self) { + int body = imm_inst(opcode, imm12&0xFFF, self, self); + return body; + } + + // for cases where rs1 and dst are the same, eg add x0, x0, 1 public static int imm_inst_l(Encoding enc, Node n, int opcode, int imm12) { short self = enc.reg(n); short reg1 = enc.reg(n.in(1)); @@ -249,17 +349,23 @@ public static int imm_inst_l(Encoding enc, Node n, int opcode, int imm12) { // for normal add, reg1, reg2 cases (reg-to-reg) // using shifted-reg form public static int r_reg(int opcode, int shift, int rm, int imm6, int rn, int rd) { + assert 0 <= rm && rm < 32; + assert 0 <= rn && rn < 32; + assert 0 <= rd && rd < 32; return (opcode << 24) | (shift << 21) | (rm << 16) | (imm6 << 10) << (rn << 5) | rd; - } - public static void r_reg(Encoding enc, Node n, int opcode) { - short self = enc.reg(n); - short reg1 = enc.reg(n.in(1)); - short reg2 = enc.reg(n.in(2)); - int body = r_reg(opcode, 0, reg2, 0, reg1, self); - enc.add4(body); + } + public static void r_reg(Encoding enc, Node n, int opcode) { + short self = enc.reg(n); + short reg1 = enc.reg(n.in(1)); + short reg2 = enc.reg(n.in(2)); + int body = r_reg(opcode, 0, reg2, 0, reg1, self >= 32 ? reg1: self); + enc.add4(body); } public static int shift_reg(int opcode, int rm, int op2, int rn, int rd) { + assert 0 <= rn && rn < 32; + assert 0 <= rm && rm < 32; + assert 0 <= rd && rd < 32; return (opcode << 21) | (rm << 16) | (op2 << 10) | (rn << 5) | rd; } public static void shift_reg(Encoding enc, Node n, int op2) { @@ -272,6 +378,9 @@ public static void shift_reg(Encoding enc, Node n, int op2) { // MUL can be considered an alias for MADD with the third operand Ra being set to 0 public static int madd(int opcode, int rm, int ra, int rn, int rd) { + assert 0 <= rn && rn < 32; + assert 0 <= rd && rd < 32; + assert 0 <= rm && rm < 32; return (opcode << 21) | (rm << 16) | (ra << 10) | (rn << 5) | rd; } public static void madd(Encoding enc, Node n, int opcode, int ra) { @@ -284,11 +393,13 @@ public static void madd(Encoding enc, Node n, int opcode, int ra) { // encodes movk, movn, and movz public static int mov(int opcode, int shift, int imm16, int rd) { + assert 0 <= rd && rd < 32; return (opcode << 23) | (shift << 21) | (imm16 << 5) | rd; } - public static int mov_reg(int opcode, int src, int dst) { - return (opcode << 21) | (src << 16) | 0b11111 << 5 | dst; + public static int mov_reg(int opcode, int src, int rd) { + assert 0 <= rd && rd < 32; + return (opcode << 21) | (src << 16) | 0b11111 << 5 | rd; } public static int ret(int opcode) { @@ -296,18 +407,21 @@ public static int ret(int opcode) { } // FMOV (scalar, immediate) - public static int f_mov(int opcode, int ftype, int imm8, int rd) { - return (opcode << 24) | (ftype << 21) |(imm8 << 13) | (128 << 5) | rd; - } - public static int f_scalar(int opcode, int ftype, int rm, int op, int rn, int rd) { + assert 0 <= rn && rn < 32; + assert 0 <= rd && rd < 32; + assert 0 <= rm && rm < 32; return (opcode << 24) | (ftype << 22) | (1 << 21) | (rm << 16) | (op << 10) | (rn << 5) | rd; } public static int f_mov_reg(int opcode, int rn, int rd) { + assert 0 <= rn && rn < 32; + assert 0 <= rd && rd < 32; return (opcode << 24) | (0b01100000010000 << 10) | (rn << 5) | rd; } public static int f_mov_general(int opcode, int ftype, int rmode, int opcode1, int rn, int rd) { + assert 0 <= rn && rn < 32; + assert 0 <= rd && rd < 32; return (opcode << 24) |(ftype << 22) | (1 << 21) | (rmode << 19) | (opcode1 << 16) | (rn << 5) | rd; } public static void f_scalar(Encoding enc, Node n, int op ) { @@ -324,19 +438,20 @@ public static int load_pc(int opcode, int offset, int rt) { } // int l public static int adrp(int op, int imlo,int opcode, int imhi, int rd) { + assert 0 <= rd && rd < 32; return (op << 31) | (imlo << 29) |(opcode << 24) | (imhi << 5) | rd; } - public static int load_adr(int opcode, int offset, int base, int rt) { - return (opcode << 22) | (offset << 10) | (base << 5) | rt; - } - // [Rptr+Roff] public static int indr_adr(int opcode, int off, STORE_LOAD_OPTION option, int s, int ptr, int rt) { + assert 0 <= ptr && ptr < 32; + assert 0 <= rt && rt < 32; return (opcode << 21) | (off << 16) | (option.ordinal() << 13) | (s << 12) | (2 << 10) | (ptr << 5) | rt; } // [Rptr+imm9] public static int load_str_imm(int opcode, int imm12, int ptr, int rt) { + assert 0 <= ptr && ptr < 32; + assert 0 <= rt && rt < 32; return (opcode << 22) | (imm12 << 10) |(ptr << 5) | rt; } @@ -351,12 +466,16 @@ public static int f_convert(int opcode_1, int opcode_2, int opcode_3, int opcode (vd << 12) | (0x01100010 << 4) | vm; } public static int float_cast(int opcode, int ftype, int rn, int rd) { + assert 0 <= rd && rd < 32; + assert 0 <= rn && rn < 32; return (opcode << 24) | (ftype << 22) | (2176 << 10) | (rn << 5) | rd; } // ftype = 3 public static int f_cmp(int opcode, int ftype, int rm, int rn) { + assert 0 <= rn && rn < 32; + assert 0 <= rm && rm < 32; return (opcode << 24) | (ftype << 21) | (rm << 16) | (8 << 10) | (rn << 5) | 8; } public static void f_cmp(Encoding enc, Node n) { @@ -386,11 +505,14 @@ public static int b_cond(int opcode, int delta, COND cond) { } public static int cond_set(int opcode, int rm, COND cond, int rn, int rd) { + assert 0 <= rd && rd < 32; + assert 0 <= rn && rn < 32; return (opcode << 21) | (rm << 16) | (cond.ordinal() << 12) | (rn << 5) | rd; } // Branch with Link to Register calls a subroutine at an address in a register, setting register X30 to PC+4. public static int blr(int opcode, int rd) { + assert 0 <= rd && rd < 32; return opcode << 10 | rd << 5; } public static int b(int opcode, int delta) { @@ -485,7 +607,7 @@ static RegMask retMask( SONTypeFunPtr tfp, int i ) { } // Break an infinite loop - @Override public IfNode never(CFGNode ctrl ) { + @Override public NeverNode never(CFGNode ctrl ) { throw Utils.TODO(); } @@ -569,7 +691,7 @@ private Node add(AddNode add) { private Node sub(SubNode sub) { return sub.in(2) instanceof ConstantNode con && con._con instanceof SONTypeInteger ti && imm12(ti) - ? new SubIARM(sub, (int)ti.value()) + ? new AddIARM(sub, (int)(-ti.value())) : new SubARM(sub); } 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 5a848a1..8691f78 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,20 +4,20 @@ 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.sontypes.SONType; // Add upper 20bits to PC. Immediate comes from the relocation info. public class AUIPC extends ConstantNode implements MachNode, RIPRelSize { - AUIPC( SONTypeFunPtr tfp ) { super(tfp); } + AUIPC( SONType tfp ) { super(tfp); } @Override public RegMask regmap(int i) { return null; } @Override public RegMask outregmap() { return riscv.WMASK; } @Override public boolean isClone() { return true; } - @Override public AUIPC copy() { return new AUIPC((SONTypeFunPtr)_con); } + @Override public AUIPC copy() { return new AUIPC(_con); } @Override public String op() { return "auipc"; } @Override public void encoding( Encoding enc ) { enc.relo(this); short dst = enc.reg(this); - enc.add4(riscv.u_type(0x17, dst, 0)); + enc.add4(riscv.u_type(riscv.OP_AUIPC, dst, 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/riscv/AddIRISC.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/AddIRISC.java index 1de9018..44ed6e0 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/AddIRISC.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/AddIRISC.java @@ -8,7 +8,7 @@ public class AddIRISC extends ImmRISC { public AddIRISC( Node add, int imm12, boolean pop ) { super(add,imm12,pop); } @Override public String op() { return "addi"; } @Override public String glabel() { return "+"; } - @Override int opcode() { return riscv.I_TYPE; } + @Override int opcode() { return riscv.OP_IMM; } @Override int func3() {return 0;} @Override public AddIRISC copy() { // Clone the AddI, using the same inputs-only code used during inst select. diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/AndIRISC.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/AndIRISC.java index b37f960..b10049d 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/AndIRISC.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/AndIRISC.java @@ -4,9 +4,9 @@ import com.compilerprogramming.ezlang.compiler.nodes.Node; public class AndIRISC extends ImmRISC { - AndIRISC( Node and, int imm) { super(and,imm); } + public AndIRISC( Node and, int imm) { super(and,imm); } @Override public String op() { return "andi"; } @Override public String glabel() { return "&"; } - @Override int opcode() { return riscv.I_TYPE; } + @Override int opcode() { return riscv.OP_IMM; } @Override int func3() {return 7;} } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/AndRISC.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/AndRISC.java index 01677f0..8916ddb 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/AndRISC.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/AndRISC.java @@ -5,11 +5,11 @@ import com.compilerprogramming.ezlang.compiler.nodes.*; public class AndRISC extends MachConcreteNode implements MachNode { - AndRISC(Node and) { super(and); } + public AndRISC(Node and) { super(and); } @Override public String op() { return "and"; } @Override public RegMask regmap(int i) { return riscv.RMASK; } @Override public RegMask outregmap() { return riscv.WMASK; } - @Override public void encoding( Encoding enc ) { riscv.r_type(enc,this,7,0); } + @Override public void encoding( Encoding enc ) { riscv.r_type(enc,this,0b111,0); } @Override public void asm(CodeGen code, SB sb) { sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" & ").p(code.reg(in(2))); } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/BranchRISC.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/BranchRISC.java index a6bfb29..3fe6397 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/BranchRISC.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/BranchRISC.java @@ -68,9 +68,8 @@ public BranchRISC( IfNode iff, String bop, Node n1, Node n2 ) { String src1 = in(1)==null ? "#0" : code.reg(in(1)); String src2 = in(2)==null ? "#0" : code.reg(in(2)); sb.p(src1).p(" ").p(_bop).p(" ").p(src2).p(" "); - CFGNode prj = cproj(0); - while( prj.nOuts() == 1 ) - prj = prj.uctrl(); // Skip empty blocks + CFGNode prj = cproj(0).uctrlSkipEmpty(); + if( !prj.blockHead() ) prj = prj.cfg0(); sb.p(label(prj)); } } 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 67ff05d..5b4512f 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 @@ -32,7 +32,7 @@ public class CallRISC extends CallNode implements MachNode, RIPRelSize { // Long form: auipc rX,imm20/32; jal r0,[rX+imm12/32] enc.relo(this); short rpc = enc.reg(this); - enc.add4(riscv.j_type(riscv.J_JAL, rpc, 0)); + enc.add4(riscv.j_type(riscv.OP_JAL, rpc, 0)); } // Delta is from opcode start @@ -46,7 +46,7 @@ public class CallRISC extends CallNode implements MachNode, RIPRelSize { @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.J_JAL, 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/CallRRISC.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/CallRRISC.java index c3a7757..22d08d6 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/CallRRISC.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/CallRRISC.java @@ -18,7 +18,7 @@ public class CallRRISC extends CallNode implements MachNode { @Override public void encoding( Encoding enc ) { short rpc = enc.reg(this); short src = enc.reg(in(_inputs._len-1)); - int body = riscv.i_type(0x67, rpc, 0, src, 0); + int body = riscv.i_type(riscv.OP_JALR, rpc, 0, src, 0); enc.add4(body); } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/CastRISC.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/CastRISC.java index 0bc06b3..e879d3e 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/CastRISC.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/CastRISC.java @@ -8,7 +8,7 @@ import com.compilerprogramming.ezlang.compiler.nodes.MachNode; public class CastRISC extends CastNode implements MachNode { - CastRISC( CastNode cast ) { super(cast); } + public CastRISC( 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; } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/DivRISC.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/DivRISC.java index c7482d7..efc6b96 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/DivRISC.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/DivRISC.java @@ -5,7 +5,7 @@ import com.compilerprogramming.ezlang.compiler.nodes.*; public class DivRISC extends MachConcreteNode implements MachNode{ - DivRISC(Node div) {super(div);} + public DivRISC(Node div) {super(div);} @Override public String op() { return "div"; } @Override public RegMask regmap(int i) { return riscv.RMASK; } @Override public RegMask outregmap() { return riscv.WMASK; } 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 0a477dd..32e205d 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 @@ -16,13 +16,15 @@ 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); + enc.largeConstant(this,_con, 0, -1/*TODO: RISC5 style patching*/); short dst = (short)(enc.reg(this) - riscv.F_OFFSET); + short tmp = (short)riscv.T6; // AUIPC dst,#hi20_constant_pool - enc.add4(riscv.u_type(0b0010111, dst, 0)); + enc.add4(riscv.u_type(riscv.OP_AUIPC, tmp, 0)); // Load dst,[dst+#low12_constant_pool] - enc.add4(riscv.i_type(0x07, dst, 0x03, dst, 0)); + 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. // TODO: always size 8? @@ -31,10 +33,11 @@ public class FltRISC extends ConstantNode implements MachNode, RIPRelSize { // Delta is from opcode start @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { short dst = (short)(enc.reg(this) - riscv.F_OFFSET); + short tmp = (short)riscv.T6; // AUIPC dst,#hi20_constant_pool - enc.patch4(opStart , riscv.u_type(0b0010111, dst, delta)); + enc.patch4(opStart , riscv.u_type(riscv.OP_AUIPC, tmp, delta)); // Load dst,[dst+#low12_constant_pool] - enc.patch4(opStart+4, riscv.i_type(0x07, dst, 0x03, dst, delta)); + enc.patch4(opStart+4, riscv.i_type(riscv.OP_LOAD, dst, 0b11, tmp, delta)); } @Override public void asm(CodeGen code, SB sb) { diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/FunRISC.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/FunRISC.java index 6f7b98d..c06a40c 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/FunRISC.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/FunRISC.java @@ -27,7 +27,7 @@ public class FunRISC extends FunNode implements MachNode { _maxArgSlot = riscv.maxSlot(enc._fun.sig()); _frameAdjust = (short) (_maxSlot+1 - _maxArgSlot); if( _frameAdjust == 0 ) return; // Skip if no frame adjust - enc.add4(riscv.i_type(riscv.I_TYPE, riscv.SP, 0, riscv.SP, (_frameAdjust*8) & 0xFFF)); + enc.add4(riscv.i_type(riscv.OP_IMM, riscv.SP, 0, riscv.SP, (_frameAdjust*8) & 0xFFF)); } @Override public void asm(CodeGen code, SB sb) { diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/I2F8RISC.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/I2F8RISC.java index 00854e4..4202af5 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/I2F8RISC.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/I2F8RISC.java @@ -14,7 +14,7 @@ public class I2F8RISC extends MachConcreteNode implements MachNode { @Override public void encoding( Encoding enc ) { short dst = (short)(enc.reg(this )-riscv.F_OFFSET); short src1 = enc.reg(in(1)); - int body = riscv.r_type(0b1010011,dst,riscv.RM.RNE.ordinal(),src1,0,0x69); + int body = riscv.r_type(riscv.OP_FP,dst,riscv.RM.RNE.ordinal(),src1,0,0x69); enc.add4(body); } @Override public void asm(CodeGen code, SB sb) { 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 635155e..c230467 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 @@ -20,7 +20,7 @@ public class IntRISC extends ConstantNode implements MachNode { SONTypeInteger ti = (SONTypeInteger)_con; // Explicit truncation of larger immediates; this will sign-extend on // load and this is handled during instruction selection. - enc.add4(riscv.i_type(riscv.I_TYPE, dst, 0, riscv.ZERO, (int)(ti.value() & 0xFFF))); + enc.add4(riscv.i_type(riscv.OP_IMM, dst, 0, riscv.ZERO, (int)(ti.value() & 0xFFF))); } @Override public void asm(CodeGen code, SB sb) { String reg = code.reg(this); 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 a85eba9..e63e001 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 @@ -21,7 +21,7 @@ public LUI( int imm20 ) { long x = ((SONTypeInteger)_con).value(); int imm20 = (int)(x>>12) & 0xFFFFF; short dst = enc.reg(this); - int lui = riscv.u_type(0x17, dst, imm20); + int lui = riscv.u_type(riscv.OP_LUI, dst, imm20); enc.add4(lui); } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/LoadRISC.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/LoadRISC.java index d3e6479..89e1f0f 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/LoadRISC.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/LoadRISC.java @@ -10,15 +10,16 @@ // idx = null // off = off - imm12 added to base public class LoadRISC extends MemOpRISC { - LoadRISC(LoadNode ld, Node base, int off) { super(ld, base, off, null); } + public LoadRISC(LoadNode ld, Node base, int off) { super(ld, base, off, null); } @Override public String op() { return "ld" +_sz; } @Override public RegMask regmap(int i) { return riscv.RMASK; } @Override public RegMask outregmap() { return riscv.MEM_MASK; } @Override public void encoding( Encoding enc ) { - short dst = xreg(enc); + short dst = enc.reg(this ); short ptr = enc.reg(ptr()); - int body = riscv.i_type(opcode(enc), dst, func3(), ptr, _off); - enc.add4(body); + int op = dst >= riscv.F_OFFSET ? riscv.OP_LOADFP : riscv.OP_LOAD; + if( dst >= riscv.F_OFFSET ) dst -= riscv.F_OFFSET; + enc.add4(riscv.i_type(op, dst, func3(), ptr, _off)); } @Override public void asm(CodeGen code, SB sb) { 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 23988e6..c66f079 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 @@ -9,7 +9,7 @@ public abstract class MemOpRISC extends MemOpNode implements MachNode { final int _off; // Limit 12 bits - final char _sz = (char)('0'+(1<<_declaredType.log_size())); + final char _sz; MemOpRISC(MemOpNode mop, Node base, int off, Node val) { super(mop,mop); assert base._type instanceof SONTypeMemPtr; @@ -17,6 +17,7 @@ public abstract class MemOpRISC extends MemOpNode implements MachNode { _inputs.setX(3, null); // Never an index _inputs.setX(4, val ); _off = off; + _sz = (char)('0'+(1<<_declaredType.log_size())); } @Override public String label() { return op(); } @@ -30,14 +31,24 @@ public abstract class MemOpRISC extends MemOpNode implements MachNode { // func3 is based on load/store size and extend int func3() { int func3 = -1; - if( _declaredType == SONTypeInteger. I8 ) func3=0; // LB SB - if( _declaredType == SONTypeInteger.I16 ) func3=1; // LH SH - if( _declaredType == SONTypeInteger.I32 ) func3=2; // LW SW - if( _declaredType == SONTypeInteger.BOT ) func3=3; // LD SD + // 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( 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 + // float if(_declaredType == SONTypeFloat.F32) func3 = 2; // fLW fSW if(_declaredType == SONTypeFloat.F64) func3 = 3; // fLD fSD @@ -46,19 +57,6 @@ int func3() { return func3; } - // 7 bits, 00 000 11 or 00 001 11 for FP - int opcode(Encoding enc) { - if( enc.reg(this) < riscv.F_OFFSET ) return 3; - else if( this instanceof StoreRISC ) - // opcode is the same for 32 bit and 64 bits - return 39; - return 7; - } - short xreg(Encoding enc) { - short xreg = enc.reg(this ); - return xreg < riscv.F_OFFSET ? xreg : (short)(xreg-riscv.F_OFFSET); - } - // Register mask allowed on input i. @Override public RegMask regmap(int i) { // 0 - ctrl diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/MulRISC.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/MulRISC.java index 1930da7..585cc1f 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/MulRISC.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/MulRISC.java @@ -6,7 +6,7 @@ // mulh signed multiply instruction(no-imm form) public class MulRISC extends MachConcreteNode implements MachNode{ - MulRISC(Node mul) {super(mul);} + public MulRISC(Node mul) {super(mul);} @Override public String op() { return "mul"; } @Override public RegMask regmap(int i) { assert i==1 || i==2; return riscv.RMASK; } @Override public RegMask outregmap() { return riscv.WMASK; } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/NJmpRISC.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/NJmpRISC.java new file mode 100644 index 0000000..d7d6e2e --- /dev/null +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/NJmpRISC.java @@ -0,0 +1,46 @@ +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.*; +import com.compilerprogramming.ezlang.compiler.sontypes.SONTypeFunPtr; +import java.util.BitSet; + +public class NJmpRISC extends NeverNode implements MachNode, RIPRelSize { + // label is obtained implicitly + public NJmpRISC( CFGNode cfg ) { super(cfg); } + + @Override public String op() { return "jmp"; } + @Override public String label() { return op(); } + @Override public String comment() { return "L"+cproj(1)._nid; } + @Override public StringBuilder _print1( StringBuilder sb, BitSet visited ) { return sb.append("jmp "); } + @Override public RegMask regmap(int i) { throw Utils.TODO(); } + @Override public RegMask outregmap() { return null; } + + @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.jump(this,cproj(0)); + enc.add4(riscv.j_type(riscv.OP_JAL, 0, 0)); + } + + // Delta is from opcode start + @Override public byte encSize(int delta) { + if( -(1L<<20) <= delta && delta < (1L<<20) ) return 4; + // 2 word encoding needs a tmp register, must teach RA + throw Utils.TODO(); + } + + // Delta is from opcode start + @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { + if( opLen==4 ) { + enc.patch4(opStart,riscv.j_type(riscv.OP_JAL, 0, delta)); + } else { + throw Utils.TODO(); + } + } + + @Override public void asm(CodeGen code, SB sb) { + sb.p(label(cproj(0).uctrl())); + } +} diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/NewRISC.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/NewRISC.java index a561f3b..8c3fbeb 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/NewRISC.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/NewRISC.java @@ -16,14 +16,13 @@ public class NewRISC extends NewNode implements MachNode { @Override public RegMask outregmap() { return null; } @Override public RegMask killmap() { return riscv.riscCallerSave(); } - // Encoding is appended into the byte array; size is returned @Override public void encoding( Encoding enc ) { // Generic external encoding; 2 ops. enc.external(this,"calloc"); // A1 is a caller-save, allowed to crush building external address // auipc - enc.add4(riscv.u_type(0x17, riscv.A1, 0)); - enc.add4(riscv.i_type(0x67, riscv.RPC, 0, riscv.A1, 0)); + enc.add4(riscv.u_type(riscv.OP_AUIPC, riscv.A1, 0)); + enc.add4(riscv.i_type(riscv.OP_JALR, riscv.RPC, 0, riscv.A1, 0)); } // General form: "alloc #bytes PC" diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/NotRISC.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/NotRISC.java index 94d2a92..81b568a 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/NotRISC.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/NotRISC.java @@ -10,7 +10,7 @@ public class NotRISC extends ImmRISC { @Override public RegMask outregmap() { return riscv.RMASK; } @Override public String op() { return "not"; } // sltiu: x 0 ) - enc.add4(riscv.i_type(riscv.I_TYPE, riscv.SP, 0, riscv.SP, (frameAdjust*-8) & 0xFFF)); + enc.add4(riscv.i_type(riscv.OP_IMM, riscv.SP, 0, riscv.SP, (frameAdjust*-8) & 0xFFF)); short rpc = enc.reg(rpc()); - enc.add4(riscv.i_type(0x67, riscv.ZERO, 0, rpc, 0)); + enc.add4(riscv.i_type(riscv.OP_JALR, riscv.ZERO, 0, rpc, 0)); } @Override public void asm(CodeGen code, SB sb) { @@ -41,7 +41,7 @@ public RetRISC(ReturnNode ret, FunNode fun) { // Prints return reg (either A0 or FA0), RPC (always R1) and then // the callee-save registers. for( int i=2; i= riscv.MAX_REG ) { throw Utils.TODO(); // Very rare stack-stack move } - int off = enc._fun.computeStackSlot(dst - riscv.MAX_REG)*8; - // store 64 bit values - enc.add4(riscv.s_type(39, 3, riscv.SP, dst, off)); + int op = srcX ? riscv.OP_STOREFP : riscv.OP_STORE; + if( srcX ) src -= riscv.F_OFFSET; + enc.add4(riscv.s_type(op, 0b011, riscv.SP, src, off)); + return; } if( src >= riscv.MAX_REG ) { // Load from SP int off = enc._fun.computeStackSlot(src - riscv.MAX_REG)*8; - enc.add4(riscv.i_type(7, dst, 3,riscv.SP, off)); + int op = dstX ? riscv.OP_LOADFP : riscv.OP_LOAD; + if( dstX ) dst -= riscv.F_OFFSET; + enc.add4(riscv.i_type(op, dst, 0b011, riscv.SP, off)); + return; } // pick opcode based on regs if( !dstX && !srcX ) { @@ -38,17 +42,17 @@ public class SplitRISC extends SplitNode { enc.add4(riscv.r_type(riscv.OP,dst,0,src,riscv.ZERO,0)); } else if( dstX && srcX ) { // FPR->FPR - // Can do: FPR->GPR->FPR - enc.add4(riscv.r_type(0b1010011, dst, 0, src, 0, 0b1110001)); - enc.add4(riscv.r_type(0b1010011, dst, 0, src, 0, 0b0100000)); - } else if( dstX && !srcX ) { + src -= riscv.F_OFFSET; + dst -= riscv.F_OFFSET; + enc.add4(riscv.r_type(riscv.OP_FP, dst, 0b000, src, src, 0b0010101)); // dst = FMIN(src,src) + } else if(!srcX && dstX) { //GPR->FPR // fmv.d.x - enc.add4(riscv.r_type(0b1010011, dst, 0, src, 0, 0b0100000)); - } else if( !dstX && srcX ) { + enc.add4(riscv.r_type(riscv.OP_FP, dst - riscv.F_OFFSET, 0, src, 0, 0b1111001)); + } else if(srcX && !dstX) { //FPR->GPR //fmv.x.d - enc.add4(riscv.r_type(0b1010011, dst, 0, src, 0, 0b1110001)); + enc.add4(riscv.r_type(riscv.OP_FP, dst, 0, src - riscv.F_OFFSET, 0, 0b1110001)); } } 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 95b66c7..2ccf60a 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,8 +4,8 @@ import com.compilerprogramming.ezlang.compiler.nodes.Node; public class SraIRISC extends ImmRISC { - SraIRISC( Node and, int imm) { super(and,imm); } - @Override int opcode() { return riscv.I_TYPE; } + public SraIRISC( Node and, int imm) { super(and,imm); } + @Override int opcode() { return riscv.OP_IMM; } @Override int func3() { return 5;} @Override public String glabel() { return ">>"; } @Override public String op() { return "srai"; } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/SraRISC.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/SraRISC.java index 9d919cb..61cd5aa 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/SraRISC.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/SraRISC.java @@ -6,11 +6,11 @@ // Right Shift Arithmetic public class SraRISC extends MachConcreteNode implements MachNode { - SraRISC(Node sra) { super(sra); } + public SraRISC(Node sra) { super(sra); } @Override public String op() { return "sar"; } @Override public RegMask regmap(int i) { return riscv.RMASK; } @Override public RegMask outregmap() { return riscv.WMASK; } - @Override public void encoding( Encoding enc ) { riscv.r_type(enc,this,5,0x20); } + @Override public void encoding( Encoding enc ) { riscv.r_type(enc,this,0b101,0b00100000); } @Override public void asm(CodeGen code, SB sb) { sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" >> ").p(code.reg(in(2))); } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/SrlIRISC.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/SrlIRISC.java index a19c72b..45da4c4 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/SrlIRISC.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/SrlIRISC.java @@ -4,8 +4,8 @@ import com.compilerprogramming.ezlang.compiler.nodes.Node; public class SrlIRISC extends ImmRISC { - SrlIRISC( Node and, int imm, boolean pop) { super(and,imm,pop); } - @Override int opcode() { return riscv.I_TYPE; } + public SrlIRISC( Node and, int imm, boolean pop) { super(and,imm,pop); } + @Override int opcode() { return riscv.OP_IMM; } @Override int func3() { return 5; } @Override public String glabel() { return ">>>"; } @Override public String op() { return "srli"; } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/SrlRISC.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/SrlRISC.java index 37b7059..d3c09f0 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/SrlRISC.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/SrlRISC.java @@ -6,7 +6,7 @@ // Right Shift Logical public class SrlRISC extends MachConcreteNode implements MachNode { - SrlRISC(Node srli) { super(srli); } + public SrlRISC(Node srli) { super(srli); } @Override public String op() { return "shr"; } @Override public RegMask regmap(int i) { return riscv.RMASK; } @Override public RegMask outregmap() { return riscv.WMASK; } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/StoreRISC.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/StoreRISC.java index 7f16a1b..7a76f55 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/StoreRISC.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/StoreRISC.java @@ -32,10 +32,11 @@ public class StoreRISC extends MemOpRISC { @Override public RegMask outregmap() { return null; } @Override public void encoding( Encoding enc ) { - short val = xreg(enc); + short val = enc.reg(val()); short ptr = enc.reg(ptr()); - int body = riscv.s_type(opcode(enc), func3()&3, ptr, val, _off); - enc.add4(body); + int op = val >= riscv.F_OFFSET ? riscv.OP_STOREFP : riscv.OP_STORE; + if( val >= riscv.F_OFFSET ) val -= riscv.F_OFFSET; + enc.add4(riscv.s_type(op, func3()&7, ptr, val, _off)); } @Override public void asm(CodeGen code, SB sb) { diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/SubRISC.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/SubRISC.java index 652210f..76be3ef 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/SubRISC.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/SubRISC.java @@ -5,7 +5,7 @@ import com.compilerprogramming.ezlang.compiler.nodes.*; public class SubRISC extends MachConcreteNode implements MachNode { - SubRISC( Node sub ) { super(sub); } + public SubRISC( Node sub ) { super(sub); } @Override public String op() { return "sub"; } @Override public RegMask regmap(int i) { assert i==1 || i==2; return riscv.RMASK; } @Override public RegMask outregmap() { return riscv.WMASK; } 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 e0cf2df..d04275d 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 @@ -19,9 +19,9 @@ public class TFPRISC extends ConstantNode implements MachNode, RIPRelSize { short dst = enc.reg(this); SONTypeFunPtr tfp = (SONTypeFunPtr)_con; // auipc t0,0 - int auipc = riscv.u_type(0b0010111, dst, 0); + int auipc = riscv.u_type(riscv.OP_AUIPC, dst, 0); // addi t1,t0 + #0 - int addi = riscv.i_type(0b0010011, dst, 0, dst, 0); + int addi = riscv.i_type(riscv.OP_IMM, dst, 0, dst, 0); enc.add4(auipc); enc.add4(addi); } @@ -34,15 +34,16 @@ public class TFPRISC extends ConstantNode 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 ) { + if( opLen==8 ) { // AUIPC (upper 20 bits) // opstart of add int next = opStart + opLen; - enc.patch4(opStart,riscv.u_type(0b0010111, rpc, delta)); + enc.patch4(opStart,riscv.u_type(riscv.OP_AUIPC, rpc, delta)); // addi(low 12 bits) - enc.patch4(next,riscv.i_type(0b0010011, rpc, 0, rpc, delta & 0xFFF)); + enc.patch4(next,riscv.i_type(riscv.OP_IMM, rpc, 0, rpc, delta & 0xFFF)); // addi } else { + // should not happen as one instruction is 4 byte, and TFP arm encodes 2. throw Utils.TODO(); } } 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 ca5087c..07959cf 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 @@ -8,12 +8,9 @@ // unconditional jump public class UJmpRISC extends CFGNode implements MachNode, RIPRelSize { - //UJmpRISC() { } @Override public String op() { return "jmp"; } @Override public String label() { return op(); } - @Override public StringBuilder _print1( StringBuilder sb, BitSet visited ) { - return sb.append("jmp "); - } + @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(); } @@ -22,7 +19,7 @@ public class UJmpRISC extends CFGNode implements MachNode, RIPRelSize { // Short form +/-4K: beq r0,r0,imm12 // Long form: auipc rX,imm20/32; jal r0,[rX+imm12/32] enc.jump(this,uctrl()); - enc.add4(riscv.j_type(riscv.J_JAL, 0, 0)); + enc.add4(riscv.j_type(riscv.OP_JAL, 0, 0)); } // Delta is from opcode start @@ -35,7 +32,7 @@ public class UJmpRISC extends CFGNode implements MachNode, RIPRelSize { // Delta is from opcode start @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { if( opLen==4 ) { - enc.patch4(opStart,riscv.j_type(riscv.J_JAL, 0, delta)); + enc.patch4(opStart,riscv.j_type(riscv.OP_JAL, 0, delta)); } else { throw Utils.TODO(); } 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 0f2338c..b7c03b0 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 @@ -4,8 +4,8 @@ import com.compilerprogramming.ezlang.compiler.nodes.Node; public class XorIRISC extends ImmRISC { - XorIRISC( Node and, int imm) { super(and,imm); } - @Override int opcode() { return riscv.I_TYPE; } + public XorIRISC( Node and, int imm) { super(and,imm); } + @Override int opcode() { return riscv.OP_IMM; } @Override int func3() { return 4; } @Override public String glabel() { return "^"; } @Override public String op() { return "xori"; } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/XorRISC.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/XorRISC.java index 2542201..0d77e5e 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/XorRISC.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/riscv/XorRISC.java @@ -5,7 +5,7 @@ import com.compilerprogramming.ezlang.compiler.nodes.*; public class XorRISC extends MachConcreteNode implements MachNode { - XorRISC(Node or) { super(or); } + public XorRISC(Node or) { super(or); } @Override public String op() { return "xor"; } @Override public RegMask regmap(int i) { return riscv.RMASK; } @Override public RegMask outregmap() { return riscv.WMASK; } 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 7cead1f..c9adfeb 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 @@ -101,22 +101,34 @@ public riscv(CodeGen code) { FA6_MASK, FA7_MASK }; - // + // major opcode: OP - public static int OP = 0b01_100_11; - public static int OP_FP = 0b10_100_11; + public static int OP_LOAD = 0b00_000_11; + public static int OP_LOADFP = 0b00_001_11; public static int OP_CUSTOM0 = 0b00_010_11; - public static int OP_BRANCH = 0b11_000_11; + public static int OP_IMM = 0b00_100_11; + public static int OP_AUIPC = 0b00_101_11; - //I_type opcode: 0010 0011 - public static int I_TYPE = 0x13; + public static int OP_STORE = 0b01_000_11; + public static int OP_STOREFP = 0b01_001_11; + public static int OP_CUSTOM1 = 0b01_010_11; + public static int OP = 0b01_100_11; + public static int OP_LUI = 0b01_101_11; - // 0110 0111 - public static int J_JAL = 0b1101111; + public static int OP_CUSTOM2 = 0b10_010_11; + public static int OP_FP = 0b10_100_11; + + public static int OP_BRANCH = 0b11_000_11; + public static int OP_JALR = 0b11_001_11; + public static int OP_RESERVED= 0b11_010_11; + public static int OP_JAL = 0b11_011_11; // Since riscv instructions are fixed we can just or them togehter public static int r_type(int opcode, int rd, int func3, int rs1, int rs2, int func7) { + assert 0 <= rs1 && rs1 < 32; + assert 0 <= rs2 && rs2 < 32; + assert 0 <= rd && rd < 32; return (func7 << 25) | (rs2 << 20) | (rs1 << 15) | (func3 << 12) | (rd << 7) | opcode; } public static void r_type(Encoding enc, Node n, int func3, int func7) { @@ -126,6 +138,7 @@ public static void r_type(Encoding enc, Node n, int func3, int func7) { int body = r_type(OP,dst,func3,src1,src2,func7); enc.add4(body); } + public static void rf_type(Encoding enc, Node n, RM func3, int func7) { short dst = (short)(enc.reg(n )-F_OFFSET); short src1 = (short)(enc.reg(n.in(1))-F_OFFSET); @@ -136,11 +149,13 @@ public static void rf_type(Encoding enc, Node n, RM func3, int func7) { public static int u_type(int opcode, int rd, int imm20) { + assert 0 <= rd && rd < 32; return (imm20 << 12) | (rd << 7) | opcode; } public static int j_type(int opcode, int rd, int delta) { assert -(1L<<20) <= delta && delta < (1L<<20); + assert 0 <= rd && rd < 32; // Messy branch offset encoding // 31 30-21 20 19-12 11-7 6-0 // 20 10- 1 11 19-12 rpc JAL @@ -149,22 +164,25 @@ public static int j_type(int opcode, int rd, int delta) { int imm11 = (delta>>11) & 1; int imm12_19 = (delta>>12) & 0xFF; int imm20 = (delta>>19) & 1; - int bits = imm20<<20 | imm12_19 << 12 | imm11 << 11 | imm10_01; + int bits = imm20<<19 | imm10_01 << 9 | imm11 << 8 | imm12_19; return bits << 12 | rd << 7 | opcode; } public static int i_type(int opcode, int rd, int func3, int rs1, int imm12) { - assert opcode >= 0 && rd >=0 && func3 >=0 && rs1 >=0 && imm12 >= 0; // Zero-extend by caller + assert 0 <= rd && rd < 32; + assert 0 <= rs1 && rs1 < 32; + assert opcode >= 0 && func3 >=0 && imm12 >= 0; // Zero-extend by caller return (imm12 << 20) | (rs1 << 15) | (func3 << 12) | (rd << 7) | opcode; } // S-type instructions(store) - public static int s_type(int opcode, int offset1, int func3, int rs1, int rs2, int offset2) { - return (offset2 << 25) | (rs2 << 20) | (rs1 << 15) | (func3 << 12) | (offset1 << 7) | opcode; - } public static int s_type(int opcode, int func3, int rs1, int rs2, int imm12) { + assert 0 <= rs1 && rs1 < 32; + assert 0 <= rs2 && rs2 < 32; + assert 0 <= func3; + assert imm12 >= 0; // Masked to high zero bits by caller int imm_lo = imm12 & 0x1F; int imm_hi = imm12 >> 5; @@ -173,6 +191,8 @@ public static int s_type(int opcode, int func3, int rs1, int rs2, int imm12) { // BRANCH public static int b_type(int opcode, int func3, short rs1, short rs2, int delta) { + assert 0 <= rs1 && rs1 < 32; + assert 0 <= rs2 && rs2 < 32; assert -4*1024 <= delta && delta < 4*1024; assert (delta&1)==0; // Low bit is always zero, not encoded // Messy branch offset encoding @@ -320,9 +340,7 @@ static RegMask retMask( SONTypeFunPtr tfp, int i ) { @Override public SplitNode split(String kind, byte round, LRG lrg) { return new SplitRISC(kind,round); } // Break an infinite loop - @Override public IfNode never( CFGNode ctrl ) { - throw Utils.TODO(); - } + @Override public NeverNode never( CFGNode ctrl ) { return new NJmpRISC(ctrl);} // True if signed 12-bit immediate public static boolean imm12(SONTypeInteger ti) { @@ -433,9 +451,9 @@ private Node cmp(BoolNode bool) { return switch( bool.op() ) { case "<" -> bool.in(2) instanceof ConstantNode con && con._con instanceof SONTypeInteger ti && imm12(ti) ? new SetIRISC(bool, (int)ti.value(),false) - : new SetRISC(bool); + : new SetRISC(bool, false); // x <= y - flip and invert; !(y < x); `slt tmp=y,x; xori dst=tmp,#1` - case "<=" -> new XorIRISC(new SetRISC(bool.swap12()),1); + case "<=" -> new XorIRISC(new SetRISC(bool.swap12(), false),1); // 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(); @@ -460,6 +478,7 @@ private Node con( ConstantNode con ) { // from a constant pool, which does not need an extra register throw Utils.TODO(); } + // Load from constant pool case SONTypeFloat tf -> new FltRISC(con); case SONTypeFunPtr tfp -> new TFPRISC(con); case SONTypeMemPtr tmp -> throw Utils.TODO(); diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/CmpIX86.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/CmpIX86.java index fe08e20..02d4e55 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/CmpIX86.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/CmpIX86.java @@ -31,7 +31,7 @@ public class CmpIX86 extends MachConcreteNode implements MachNode { @Override public Node copy() { return new CmpIX86(this); } @Override public final void encoding( Encoding enc ) { - short dst = enc.reg(this); // Also src1 + short dst = enc.reg(in(1)); // Also src1 enc.add1(x86_64_v2.rex(0, dst, 0)); // opcode; 0x81 or 0x83; 0x69 or 0x6B enc.add1( 0x81 + (x86_64_v2.imm8(_imm) ? 2 : 0) ); 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 f5d1fb5..4744dc2 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 @@ -15,16 +15,18 @@ public class CmpMemX86 extends MemOpX86 { @Override public void encoding( Encoding enc ) { // REX.W + 81 /7 id CMP r/m64, imm32 | REX.W + 39 /r CMP r/m64,r64 // CMP [mem], imm32 + short ptr = enc.reg(ptr()); short idx = enc.reg(idx()); short src = enc.reg(val()); enc.add1(x86_64_v2.rex(src, ptr, idx)); // opcode varies by immediate - enc.add1( src == -1 ? 0x39 : 0x81 ); + enc.add1( src == -1 ? 0x81 : 0x39); // includes modrm x86_64_v2.indirectAdr(_scale, idx, ptr, _off, src == -1 ? 7 : src, enc); + if( src == -1 ) enc.add4(_imm); } 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 3965433..b238ed2 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 @@ -1,15 +1,23 @@ package com.compilerprogramming.ezlang.compiler.nodes.cpus.x86_64_v2; -import com.compilerprogramming.ezlang.compiler.SB; +import com.compilerprogramming.ezlang.compiler.*; import com.compilerprogramming.ezlang.compiler.codegen.*; -import com.compilerprogramming.ezlang.compiler.nodes.Node; +import com.compilerprogramming.ezlang.compiler.nodes.*; -public class CmpX86 extends RegX86 { +public class CmpX86 extends MachConcreteNode implements MachNode { CmpX86( Node add ) { super(add); } @Override public String op() { return "cmp"; } - @Override int opcode() { return 0x3B; } + @Override public RegMask regmap(int i) { return x86_64_v2.RMASK; } @Override public RegMask outregmap() { return x86_64_v2.FLAGS_MASK; } - @Override public int twoAddress() { return 0; } + + @Override public void encoding( Encoding enc ) { + short dst = enc.reg(in(1)); + short src = enc.reg(in(2)); + + enc.add1(x86_64_v2.rex(dst, src, 0)); + enc.add1(0x3B); + enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, dst, src)); + } @Override public void asm(CodeGen code, SB sb) { String dst = code.reg(this); if( dst!="flags" ) sb.p(dst).p(" = "); diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/FltX86.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/FltX86.java index a351d6b..7003825 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/FltX86.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/FltX86.java @@ -4,7 +4,7 @@ import com.compilerprogramming.ezlang.compiler.codegen.*; import com.compilerprogramming.ezlang.compiler.nodes.*; -public class FltX86 extends ConstantNode implements MachNode, RIPRelSize { +public class FltX86 extends ConstantNode implements MachNode, RIPRelSize{ private byte _encSize; FltX86(ConstantNode con ) { super(con); } @Override public String op() { return "ld8"; } @@ -19,7 +19,6 @@ public class FltX86 extends ConstantNode implements MachNode, RIPRelSize { // F2 0F 10 /r MOVSD xmm1, m64 _encSize = 1/*Fop*/+0/*REX*/+2/*op*/+1/*MODRM*/+4/*offset*/; short dst = (short)(enc.reg(this ) - x86_64_v2.XMM_OFFSET); - enc.largeConstant(this,_con); // Fopcode enc.add1(0xF2); // rex prefix must come next (REX.W is not set) @@ -28,6 +27,7 @@ public class FltX86 extends ConstantNode implements MachNode, RIPRelSize { // hard-code rip here enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.INDIRECT, dst, 0x05)); enc.add4(0); + enc.largeConstant(this,_con,_encSize-4,2/*ELF encoding PC32*/); } // Delta is from opcode start diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/JmpX86.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/JmpX86.java index 426dde7..d6947bf 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/JmpX86.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/JmpX86.java @@ -32,8 +32,6 @@ public class JmpX86 extends IfNode implements MachNode, RIPRelSize { int op = x86_64_v2.jumpop(_bop); enc.add1(op-16); // Short form jump enc.add1(0); // Offset - //enc.add1(0x0F).add1(x86_64_v2.jumpop(_bop)); - //enc.add4(0); // Offset patched later } // Delta is from opcode start, but X86 measures from the end of the 2-byte encoding @@ -59,9 +57,8 @@ public class JmpX86 extends IfNode implements MachNode, RIPRelSize { @Override public void asm(CodeGen code, SB sb) { String src = code.reg(in(1)); if( src!="flags" ) sb.p(src).p(" "); - CFGNode prj = cproj(0); // 0 is True is jump target - while( prj.nOuts() == 1 && !(prj instanceof ReturnNode) ) - prj = prj.uctrl(); // Skip empty blocks + CFGNode prj = cproj(0).uctrlSkipEmpty(); // 0 is True is jump target + if( !prj.blockHead() ) prj = prj.cfg0(); sb.p(label(prj)); } 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 1f5dc56..0412888 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 @@ -1,12 +1,14 @@ 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.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; public class LoadX86 extends MemOpX86 { LoadX86( LoadNode ld, Node base, Node idx, int off, int scale ) { @@ -18,60 +20,36 @@ public class LoadX86 extends MemOpX86 { // REX.W + 8B /r MOV r64, r/m64 // Zero extension for u8, u16 and u32 but sign extension i8, i16, i32 // Use movsx and movzx - short dst = enc.reg(this ); short ptr = enc.reg(ptr()); short idx = enc.reg(idx()); + enc(enc, _declaredType, dst, ptr, idx, _off, _scale); + } - if (_declaredType != SONTypeInteger.U32 && _declaredType != SONTypeFloat.F32 && _declaredType != SONTypeFloat.F64) { + static void enc( Encoding enc, SONType decl, short dst, short ptr, short idx, int off, int scale ) { + if( decl != SONTypeInteger.U32 && decl != SONTypeFloat.F32 && decl != SONTypeFloat.F64 ) enc.add1(x86_64_v2.rex(dst, ptr, idx)); - } - if(_declaredType == SONTypeFloat.F32) { - // F3 0F 10 /r MOVSS xmm1, m32 - enc.add1(0xF3); - enc.add1(0x0F); - enc.add1(0x10); - dst -= (short)x86_64_v2.XMM_OFFSET; - } - if(_declaredType == SONTypeFloat.F64) { - // F2 0F 10 /r MOVSD xmm1, m64 - enc.add1(0xF2); - enc.add1(0x0F); - enc.add1(0x10); + if( decl.isa(SONTypeFloat.F64) ) dst -= (short)x86_64_v2.XMM_OFFSET; - } - if(_declaredType == SONTypeInteger.I8) { - // sign extend: REX.W + 0F BE /r MOVSX r64, r/m8 - enc.add1(0x0F); - enc.add1(0xBE); - } else if(_declaredType == SONTypeInteger.I16) { - // sign extend: REX.W + 0F BF /r MOVSX r64, r/m16 - enc.add1(0x0F); - enc.add1(0xBF); - } else if(_declaredType == SONTypeInteger.I32) { - // sign extend: REX.W + 63 /r MOVSXD r64, r/m32 - enc.add1(0x63); - } else if(_declaredType == SONTypeInteger.U8) { - // zero extend: REX.W + 0F B6 /r MOVZX r64, r/m8 - enc.add1(0x0F); - enc.add1(0xB6); - } else if(_declaredType == SONTypeInteger.U16) { - // zero extend: REX.W + 0F B7 /r MOVZX r64, r/m16 - enc.add1(0x0F); - enc.add1(0xB7); - } else if(_declaredType == SONTypeInteger.U32) { - // zero extend: 8B /r MOV r32, r/m32 - enc.add1(0x8B); - } else if(_declaredType == SONTypeInteger.BOT) { - // REX.W + 8B /r MOV r64, r/m64 - enc.add1(0x8B); - } + + if( false ) ; + else if( decl == SONTypeFloat.F32 ) enc.add1(0xF3).add1(0x0F).add1(0x10); // F3 0F 10 /r MOVSS xmm1, m32 + else if( decl == SONTypeFloat.F64 ) enc.add1(0xF2).add1(0x0F).add1(0x10); // F2 0F 10 /r MOVSD xmm1, m64 + else if( decl == 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 + // 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(); // includes modrm internally - x86_64_v2.indirectAdr(_scale, idx, ptr, _off, dst, enc); + x86_64_v2.indirectAdr(scale, idx, ptr, off, dst, enc); } + // General form: "ldN dst,[base + idx<<2 + 12]" @Override public void asm(CodeGen code, SB sb) { sb.p(code.reg(this)).p(","); 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 f511e97..dde6bca 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 @@ -14,7 +14,7 @@ // mem - memory dependence edge // base - Basic object pointer // idx/null - Scaled index offset, or null if none -// val/null - Value to store, as part of a op-to-mem or op-from-mem. Null for loads, or if an immediate is being used +// val/null - Value to store, as part of an op-to-mem or op-from-mem. Null for loads, or if an immediate is being used // Constants: // offset - offset added to base. Can be zero. // scale - scale on index; only 0,1,2,4,8 allowed, 0 is only when index is null 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 fc49513..8a5e305 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 @@ -12,8 +12,9 @@ public abstract class RegX86 extends MachConcreteNode { abstract int opcode(); @Override public void encoding( Encoding enc ) { // REX.W + 01 /r - short dst = enc.reg(this ); // src1 + short dst = enc.reg(in(1)); // src1 short src = enc.reg(in(2)); // src2 + enc.add1(x86_64_v2.rex(dst, src, 0)); enc.add1(opcode()); // opcode enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, dst, src)); diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/SarIX86.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/SarIX86.java index ac1a420..656e84a 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/SarIX86.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/SarIX86.java @@ -1,12 +1,39 @@ 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.MachNode; import com.compilerprogramming.ezlang.compiler.nodes.Node; +import com.compilerprogramming.ezlang.compiler.nodes.*; + // Arithmetic Right Shift -public class SarIX86 extends ImmX86 { - SarIX86( Node add, int imm ) { super(add,imm); assert x86_64_v2.imm8(imm); } +public class SarIX86 extends MachConcreteNode implements MachNode { + final int _imm; + SarIX86( Node sari, int imm ) { super(sari); assert x86_64_v2.imm8(imm); _inputs.pop(); _imm = imm; } @Override public String op() { return "sari"; } @Override public String glabel() { return ">>"; } - @Override int opcode() { return 0xC1; } - @Override int mod() { return 7; } + int opcode() { return 0xC1; } + int mod() { return 7; } + + @Override public RegMask regmap(int i) { return x86_64_v2.RMASK; } + @Override public RegMask outregmap() { return x86_64_v2.WMASK; } + + @Override public void encoding(Encoding enc) { + short dst = enc.reg(this); // Also src1 + enc.add1(x86_64_v2.rex(0, dst, 0)); + enc.add1( opcode()); + + enc.add1( x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, mod(), dst) ); + + // immediate(4 bytes) 32 bits or (1 byte)8 bits + if( x86_64_v2.imm8(_imm) ) enc.add1(_imm); + else enc.add4(_imm); + } + + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" ").p(glabel()).p("= #").p(_imm); + } } 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 7ee2305..df76f45 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 @@ -8,13 +8,15 @@ // Use result of comparison without jump. public class SetX86 extends MachConcreteNode implements MachNode { final String _bop; // One of <,<=,== + final boolean _unsigned; // Constructor expects input is an X86 and not an Ideal node. - SetX86( Node cmp, String bop ) { + SetX86( Node cmp, String bop, boolean unsigned ) { super(cmp); _inputs.setLen(1); // Pop the cmp inputs // Replace with the matched cmp _inputs.push(cmp); _bop = bop; + _unsigned = unsigned; } @Override public String op() { return "set"+_bop; } @Override public RegMask regmap(int i) { assert i==1; return x86_64_v2.FLAGS_MASK; } @@ -29,8 +31,8 @@ public class SetX86 extends MachConcreteNode implements MachNode { enc.add1(0x0F); // opcode enc.add1(switch (_bop) { case "==" -> 0x94; // SETE - case "<" -> 0x9C; // SETL - case "<=" -> 0X9E; // SETLE + case "<" -> _unsigned ? 0x92 : 0x9C; // SETB /SETL + case "<=" -> _unsigned ? 0x96 : 0x9E; // SETBE/SETLE default -> throw Utils.TODO(); }); enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, 0, dst)); diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/ShlIX86.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/ShlIX86.java index ee8dfb6..319a303 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/ShlIX86.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/ShlIX86.java @@ -2,10 +2,38 @@ import com.compilerprogramming.ezlang.compiler.nodes.Node; -public class ShlIX86 extends ImmX86 { - ShlIX86( Node add, int imm ) { super(add,imm); } +import com.compilerprogramming.ezlang.compiler.*; +import com.compilerprogramming.ezlang.compiler.codegen.*; +import com.compilerprogramming.ezlang.compiler.nodes.*; + +public class ShlIX86 extends MachConcreteNode implements MachNode { + final int _imm; + ShlIX86( Node shli, int imm ) { + super(shli); + assert x86_64_v2.imm8(imm); + _inputs.pop(); // Pop constant input off + _imm = imm; + } + public int opcode() { return 0xC1; } + public int mod() { return 4; } + + @Override public RegMask regmap(int i) { return x86_64_v2.RMASK; } + @Override public RegMask outregmap() { return x86_64_v2.WMASK; } + @Override public String op() { return "shli"; } @Override public String glabel() { return "<<"; } - @Override int opcode() { return 0xC1; } - @Override int mod() { return 4; } + @Override public void encoding(Encoding enc) { + short dst = enc.reg(this); // Also src1 + enc.add1(x86_64_v2.rex(0, dst, 0)); + enc.add1( opcode()); + + enc.add1( x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, mod(), dst) ); + + // immediate(4 bytes) 32 bits or (1 byte)8 bits + if( x86_64_v2.imm8(_imm) ) enc.add1(_imm); + else enc.add4(_imm); + } + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" ").p(glabel()).p("= #").p(_imm); + } } diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/ShrIX86.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/ShrIX86.java index de39108..dd0f9cb 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/ShrIX86.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/cpus/x86_64_v2/ShrIX86.java @@ -2,10 +2,33 @@ import com.compilerprogramming.ezlang.compiler.nodes.Node; -public class ShrIX86 extends ImmX86 { - ShrIX86( Node add, int imm ) { super(add,imm); } +import com.compilerprogramming.ezlang.compiler.*; +import com.compilerprogramming.ezlang.compiler.codegen.*; +import com.compilerprogramming.ezlang.compiler.nodes.*; + +public class ShrIX86 extends MachConcreteNode implements MachNode { + final int _imm; + ShrIX86( Node shri, int imm ) { super(shri); assert x86_64_v2.imm8(imm); _inputs.pop(); _imm = imm; } @Override public String op() { return "shri"; } @Override public String glabel() { return ">>>"; } - @Override int opcode() { return 0xC1; } - @Override int mod() { return 5; } + int opcode() { return 0xC1; } + int mod() { return 5; } + + @Override public RegMask regmap(int i) { return x86_64_v2.RMASK; } + @Override public RegMask outregmap() { return x86_64_v2.WMASK; } + + @Override public void encoding(Encoding enc) { + short dst = enc.reg(this); // Also src1 + enc.add1(x86_64_v2.rex(0, dst, 0)); + enc.add1( opcode()); + + enc.add1( x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, mod(), dst) ); + + // immediate(4 bytes) 32 bits or (1 byte)8 bits + if( x86_64_v2.imm8(_imm) ) enc.add1(_imm); + else enc.add4(_imm); + } + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" ").p(glabel()).p("= #").p(_imm); + } } 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 49129a2..fefefc3 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 @@ -5,6 +5,9 @@ import com.compilerprogramming.ezlang.compiler.codegen.*; 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; public class SplitX86 extends SplitNode { SplitX86( String kind, byte round ) { super(kind,round, new Node[2]); } @@ -18,12 +21,12 @@ public class SplitX86 extends SplitNode { // REX.W + 8B /r MOV r64, r/m64 short dst = enc.reg(this ); short src = enc.reg(in(1)); - if( dst == x86_64_v2.FLAGS ) { // mov reg, flags // push rcx // popf (Pop the top of the stack into the FLAGS register) // 50+rd PUSH r64 + if( src >= 8 ) x86_64_v2.rex(0,src,0,true); enc.add1(0x50 + src); // popf enc.add1(0x9D); @@ -34,6 +37,7 @@ public class SplitX86 extends SplitNode { // pushf; pop reg enc.add1(0x9C); // 58+ rd POP r64 + if( dst >= 8 ) x86_64_v2.rex(0,dst,0,true); enc.add1(0x58 + dst); return; } @@ -46,20 +50,13 @@ public class SplitX86 extends SplitNode { if( dst >= x86_64_v2.MAX_REG ) { if( src >= x86_64_v2.MAX_REG ) throw Utils.TODO(); // Very rare stack-stack move - // TODO: Missing FP 0x66 prefix - if( srcX ) { src -= (short)x86_64_v2.XMM_OFFSET; enc.add1(0x66); } int off = enc._fun.computeStackSlot(dst - x86_64_v2.MAX_REG)*8; - enc.add1(x86_64_v2.rex(src, x86_64_v2.RSP, -1)); - enc.add1( 0x89 ); - x86_64_v2.indirectAdr(0, (short)-1, (short)x86_64_v2.RSP, off, src, enc); + StoreX86.encVal(enc, srcX ? SONTypeFloat.F64 : SONTypeInteger.BOT, (short)x86_64_v2.RSP, (short)-1/*index*/, src, off, 0); return; } if( src >= x86_64_v2.MAX_REG ) { - if( dstX ) { dst -= (short)x86_64_v2.XMM_OFFSET; enc.add1(0x66); } int off = enc._fun.computeStackSlot(src - x86_64_v2.MAX_REG)*8; - enc.add1(x86_64_v2.rex(dst, x86_64_v2.RSP, -1)); - enc.add1( 0x8B ); - x86_64_v2.indirectAdr(0, (short)-1, (short)x86_64_v2.RSP, off, dst, enc); + LoadX86.enc(enc, dstX ? SONTypeFloat.F64 : SONTypeInteger.BOT, dst, (short)x86_64_v2.RSP, (short)-1, off, 0); return; } @@ -80,13 +77,14 @@ public class SplitX86 extends SplitNode { enc.add1(0x0F); enc.add1(0x28); } else if( dstX && !srcX ) { - // xmm->reg (66 REX.W 0F 6E /r MOVQ xmm, r/m64) + // reg->xmm (66 REX.W 0F 6E /r MOVQ xmm, r/m64) enc.add1(0x0F); enc.add1(0x6E); } else if( !dstX && srcX ) { - // reg->xmm(66 REX.W 0F 7E /r MOVQ r/m64, xmm) + // xmm->reg(66 0F 7E /r MOVQ r/m64, xmm) enc.add1(0x0F); enc.add1(0x7E); + short tmp=src; src=dst; dst=tmp; } enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, dst, src)); 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 501121f..5728951 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 @@ -5,8 +5,8 @@ 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 java.util.BitSet; public class StoreX86 extends MemOpX86 { @@ -30,30 +30,38 @@ public class StoreX86 extends MemOpX86 { short idx = enc.reg(idx()); short src = enc.reg(val()); - int imm_op = x86_64_v2.selectOpcodeForImmStore(_imm); - if(src == -1 && _imm != 0) { - if(imm_op == -1) {enc.add1(x86_64_v2.rex(src, ptr, idx));enc.add1(0xC7); } - else enc.add1(imm_op); - } else { - if(_declaredType == SONTypeFloat.F32) {src -= (short)x86_64_v2.XMM_OFFSET; enc.add1(0xF3); enc.add1(0x0F); enc.add1(0x11);} - else if(_declaredType == SONTypeFloat.F64) {src -= (short)x86_64_v2.XMM_OFFSET; enc.add1(0xF2); enc.add1(0x0F); enc.add1(0x11);} - else if(_declaredType.log_size() == 0) enc.add1(0x88); - else if(_declaredType.log_size() == 1) enc.add1(0x89); - else if(_declaredType.log_size() == 2) enc.add1(0x89); - else if(_declaredType.log_size() == 3) {enc.add1(x86_64_v2.rex(src, ptr, idx)); enc.add1(0x89);} - } - - x86_64_v2.indirectAdr(_scale, idx, ptr, _off, src, enc); if( src == -1 ) { + // return opcode for optimised immediate store + if( x86_64_v2.imm8(_imm) ) enc.add1(0xC6); + else if( x86_64_v2.imm32(_imm) ) enc.add1(0xC7); + else enc.add1(x86_64_v2.rex(-1, ptr, idx)).add1(0xC7); + x86_64_v2.indirectAdr(_scale, idx, ptr, _off, src, enc); switch (x86_64_v2.imm_size(_imm)) { - case 8: enc.add1(_imm); break; - case 16: enc.add2(_imm); break; - case 32: enc.add4(_imm); break; - case 64: enc.add8(_imm); break; + case 8: enc.add1(_imm); break; + case 16: enc.add2(_imm); break; + case 32: enc.add4(_imm); break; + case 64: enc.add8(_imm); break; } + } else { + encVal(enc,_declaredType,ptr,idx,src,_off,_scale); } } + // Non-immediate encoding + static void encVal( Encoding enc, SONType decl, short ptr, short idx, short src, int off, int scale ) { + if( decl instanceof SONTypeFloat ) { + src -= (short)x86_64_v2.XMM_OFFSET; + enc.add1( decl==SONTypeFloat.F32 ? 0xF3 : 0xF2 ).add1(0x0F).add1(0x11); + } + else if( decl.log_size() == 0 ) enc.add1(0x88); + else if( decl.log_size() == 1 ) enc.add1(0x89); + else if( decl.log_size() == 2 ) enc.add1(0x89); + else if( decl.log_size() == 3 ) enc.add1(x86_64_v2.rex(src, ptr, idx)).add1(0x89); + + x86_64_v2.indirectAdr(scale, idx, ptr, off, src, enc); + } + + // General form: "stN [base + idx<<2 + 12],val" @Override public void asm(CodeGen code, SB sb) { asm_address(code,sb).p(","); 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 a7691d7..61035af 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 @@ -85,13 +85,18 @@ static public int jumpop(String op) { } public static int modrm(MOD mod, int reg, int m_r) { + if( reg == -1 ) reg=0; // Missing reg in this flavor // combine all the bits + assert 0 <= reg && reg < 16; + assert 0 <= m_r && m_r < 16; return (mod.ordinal() << 6) | ((reg & 0x07) << 3) | m_r & 0x07; } // 00 000 000 // same bit-layout as modrm public static int sib(int scale, int index, int base) { + assert 0 <= base && base < 16; + assert 0 <= index && index < 16; return (scale << 6) | ((index & 0x07) << 3) | base & 0x07; } @@ -103,19 +108,17 @@ public static int sib(int scale, int index, int base) { // 0 denotes no direct register public static int rex(int reg, int ptr, int idx, boolean wide) { // assuming 64 bit by default so: 0100 1000 + assert -1 <= reg && reg < 16; + assert -1 <= ptr && ptr < 16; + assert -1 <= idx && idx < 16; + int rex = wide ? REX_W : REX; - if( 8 <= reg && reg <= 15 ) rex |= 0b00000100; // REX.R - if( 8 <= ptr && ptr <= 15 ) rex |= 0b00000001; // REX.B - if( 8 <= idx && idx <= 15 ) rex |= 0b00000010; // REX.X + if( 8 <= reg ) rex |= 0b00000100; // REX.R + if( 8 <= ptr ) rex |= 0b00000001; // REX.B + if( 8 <= idx ) rex |= 0b00000010; // REX.X return rex; } - // return opcode for optimised immediate store - public static int selectOpcodeForImmStore(long imm) { - if(imm8(imm)) return 0xC6; - if(imm16(imm)) return 0xC7; - if(imm32(imm)) return 0xC7; - return -1; - } + // return the size of the immediate public static int imm_size(long imm) { if(imm8(imm)) return 8; @@ -143,26 +146,25 @@ public static byte rexF(int reg, int ptr, int idx, boolean wide, Encoding enc) { public static void indirectAdr( int scale, short index, short base, int offset, int reg, Encoding enc ) { // Assume indirect assert 0 <= base && base < 16; - assert index != RSP; + assert -1 <= index && index < 16 && index != RSP; MOD mod = MOD.INDIRECT; // is 1 byte enough or need more? if( offset != 0 ) mod = imm8(offset) - ? MOD.INDIRECT_disp8 - : MOD.INDIRECT_disp32; + ? MOD.INDIRECT_disp8 + : MOD.INDIRECT_disp32; - // needs to pick optimal displacement mod if we want to encode base - if( mod == MOD.INDIRECT && (base == RBP || base == R13) ) + if( mod == MOD.INDIRECT && (base == RBP || base == R13) ) { mod = MOD.INDIRECT_disp8; + } else if( index == -1 && (base == RSP || base == R12) ) { + index = RSP; + } - // special encoding for [base +offset] if( index == -1 ) { - // Case for mov reg, [disp] (load) - enc.add1(modrm(mod, reg == -1 ? 0 : reg, base)); + enc.add1(modrm(mod, reg, base)); } else { - // rsp is hard-coded here(0x04) - enc.add1(modrm(mod, reg, 0x04)); + enc.add1(modrm(mod, reg, x86_64_v2.RSP)); enc.add1(sib(scale, index, base)); } @@ -372,8 +374,7 @@ static RegMask retMask( SONTypeFunPtr tfp, int i ) { } // Break an infinite loop - @Override - public IfNode never(CFGNode ctrl) { + @Override public NeverNode never(CFGNode ctrl) { throw Utils.TODO(); } @@ -381,45 +382,45 @@ public IfNode never(CFGNode ctrl) { @Override public Node instSelect(Node n) { return switch (n) { - case AddFNode addf -> addf(addf); - case AddNode add -> add(add); - case AndNode and -> and(and); - case BoolNode bool -> cmp(bool); - case CallEndNode cend -> new CallEndX86(cend); - case CallNode call -> call(call); - case CastNode cast -> new CastX86(cast); - case CProjNode c -> new CProjNode(c); - case ConstantNode con -> con(con); - case DivFNode divf -> new DivFX86(divf); - case DivNode div -> new DivX86(div); - case FunNode fun -> new FunX86(fun); - case IfNode iff -> jmp(iff); - case LoadNode ld -> ld(ld); - case MemMergeNode mem -> new MemMergeNode(mem); - case MulFNode mulf -> new MulFX86(mulf); - case MulNode mul -> mul(mul); - case NewNode nnn -> new NewX86(nnn); - case NotNode not -> new NotX86(not); - case OrNode or -> or(or); - case ParmNode parm -> new ParmX86(parm); - case PhiNode phi -> new PhiNode(phi); - case ProjNode prj -> prj(prj); - case ReadOnlyNode read -> new ReadOnlyNode(read); - case ReturnNode ret -> new RetX86(ret, ret.fun()); - case SarNode sar -> sar(sar); - case ShlNode shl -> shl(shl); - case ShrNode shr -> shr(shr); - case StartNode start -> new StartNode(start); - case StopNode stop -> new StopNode(stop); - case StoreNode st -> st(st); - case SubFNode subf -> new SubFX86(subf); - case SubNode sub -> sub(sub); - case ToFloatNode tfn -> i2f8(tfn); - case XorNode xor -> xor(xor); - - case LoopNode loop -> new LoopNode(loop); - case RegionNode region -> new RegionNode(region); - default -> throw Utils.TODO(); + case AddFNode addf -> addf(addf); + case AddNode add -> add(add); + case AndNode and -> and(and); + case BoolNode bool -> cmp(bool); + case CallEndNode cend -> new CallEndX86(cend); + case CallNode call -> call(call); + case CastNode cast -> new CastX86(cast); + case CProjNode c -> new CProjNode(c); + case ConstantNode con -> con(con); + case DivFNode divf -> new DivFX86(divf); + case DivNode div -> new DivX86(div); + case FunNode fun -> new FunX86(fun); + case IfNode iff -> jmp(iff); + case LoadNode ld -> ld(ld); + case MemMergeNode mem -> new MemMergeNode(mem); + case MulFNode mulf -> new MulFX86(mulf); + case MulNode mul -> mul(mul); + case NewNode nnn -> new NewX86(nnn); + case NotNode not -> new NotX86(not); + case OrNode or -> or(or); + case ParmNode parm -> new ParmX86(parm); + case PhiNode phi -> new PhiNode(phi); + case ProjNode prj -> prj(prj); + case ReadOnlyNode read -> new ReadOnlyNode(read); + case ReturnNode ret -> new RetX86(ret, ret.fun()); + case SarNode sar -> sar(sar); + case ShlNode shl -> shl(shl); + case ShrNode shr -> shr(shr); + case StartNode start -> new StartNode(start); + case StopNode stop -> new StopNode(stop); + case StoreNode st -> st(st); + case SubFNode subf -> new SubFX86(subf); + case SubNode sub -> sub(sub); + case ToFloatNode tfn -> i2f8(tfn); + case XorNode xor -> xor(xor); + + case LoopNode loop -> new LoopNode(loop); + case RegionNode region -> new RegionNode(region); + default -> throw Utils.TODO(); }; } @@ -501,17 +502,19 @@ private Node call(CallNode call) { // Because X86 flags, a normal ideal Bool is 2 X86 ops: a "cmp" and at "setz". // Ideal If reading from a setz will skip it and use the "cmp" instead. - private static boolean invert; + private static boolean swap, unsigned; private Node cmp( BoolNode bool ) { - invert = false; + swap = unsigned = false; Node cmp = _cmp(bool); - return new SetX86(cmp, invert ? IfNode.invert(bool.op()) : bool.op()); + return new SetX86(cmp, swap ? IfNode.swap(bool.op()) : bool.op(), unsigned); } private Node _cmp(BoolNode bool) { // Float variant - if( bool.isFloat() ) + if( bool.isFloat() ) { + unsigned = true; return new CmpFX86(bool); + } Node lhs = bool.in(1); Node rhs = bool.in(2); @@ -520,14 +523,14 @@ private Node _cmp(BoolNode bool) { return new CmpMemX86(bool, address(ld), ld.ptr(), idx, off, scale, imm(rhs), val, false); if( rhs instanceof LoadNode ld && ld.nOuts() == 1 ) - return new CmpMemX86(bool, address(ld), ld.ptr(), idx, off, scale, imm(lhs), val, true); + 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()) ) return new CmpIX86(bool, (int)ti.value()); if( lhs instanceof ConstantNode con && con._con instanceof SONTypeInteger ti && imm32(ti.value()) ) { - invert = true; + swap = true; return new CmpIX86(bool, (int)ti.value(), 0.5); } @@ -559,7 +562,7 @@ private Node jmp(IfNode iff) { // Loads do not set the flags, and will need an explicit TEST BoolNode bool; if( iff.in(1) instanceof BoolNode bool0 ) bool = bool0; - else iff.setDef(1, bool=new BoolNode.EQ(iff.in(1), new ConstantNode(SONTypeInteger.ZERO))); + else iff.setDef(1, bool=new BoolNode.NE(iff.in(1), new ConstantNode(SONTypeInteger.ZERO))); return new JmpX86(iff, bool.op()); } @@ -584,20 +587,20 @@ private Node prj( ProjNode prj ) { } private Node sar(SarNode sar) { - if( sar.in(2) instanceof ConstantNode con && con._con instanceof SONTypeInteger ti ) - return new SarIX86(sar, (int)(ti.value() & 0x03f) ); + if( sar.in(2) instanceof ConstantNode con && con._con instanceof SONTypeInteger 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 ) - return new ShlIX86(shl, (int)(ti.value() & 0x03f) ); + if( shl.in(2) instanceof ConstantNode con && con._con instanceof SONTypeInteger 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 ) - return new ShrIX86(shr, (int)(ti.value() & 0x03f) ); + if( shr.in(2) instanceof ConstantNode con && con._con instanceof SONTypeInteger ti && imm8(ti.value()) ) + return new ShrIX86(shr, (int)(ti.value() & 0xff) ); return new ShrX86(shr); } @@ -610,9 +613,7 @@ private Node st (StoreNode st ){ ld.mem() == st.mem() && ld.ptr() == st.ptr() && ld.off() == st.off()) { - if( op instanceof AddNode ) - return new MemAddX86(address(st), st.ptr(), idx, off, scale, imm(op.in(2)), val); - throw Utils.TODO(); + return new MemAddX86(address(st), st.ptr(), idx, off, scale, imm(op.in(2)), val); } } 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 3c6df73..646c7e0 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 @@ -4,10 +4,7 @@ import com.compilerprogramming.ezlang.compiler.SB; import com.compilerprogramming.ezlang.compiler.codegen.Encoding; import com.compilerprogramming.ezlang.compiler.nodes.*; -import com.compilerprogramming.ezlang.compiler.sontypes.SONType; -import com.compilerprogramming.ezlang.compiler.sontypes.SONTypeFunPtr; -import com.compilerprogramming.ezlang.compiler.sontypes.SONTypeMem; -import com.compilerprogramming.ezlang.compiler.sontypes.SONTypeRPC; +import com.compilerprogramming.ezlang.compiler.sontypes.*; public abstract class ASMPrinter { @@ -29,20 +26,34 @@ public static SB print(SB sb, CodeGen code) { Encoding enc = code._encoding; if( enc!=null && !enc._bigCons.isEmpty() ) { sb.p("--- Constant Pool ------").nl(); - for( Node relo : enc._bigCons.keySet() ) { - SONType t = enc._bigCons.get(relo); - if( t.log_size()==3 ) { - sb.hex2(iadr).p(" ").hex8(enc.read8(iadr)).p(" "); - t.print(sb).nl(); - iadr += 8; - } - } - for( Node relo : enc._bigCons.keySet() ) { - SONType t = enc._bigCons.get(relo); - if( t.log_size()==2 ) { - sb.hex2(iadr).p(" ").hex4(enc.read4(iadr)).fix(9,""); - t.print(sb).nl(); - iadr += 4; + // By log size + for( int log = 3; log >= 0; log-- ) { + for( Node op : enc._bigCons.keySet() ) { + Encoding.Relo relo = enc._bigCons.get(op); + 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<>1); i++ ) - sb.hex1(code._encoding._bits.buf()[iadr++]); + if( code._asmLittle ) + for( int i=0; i>1); // Not-printed parts of encoding diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/print/IRPrinter.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/print/IRPrinter.java index a69581d..c3d38e1 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/print/IRPrinter.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/print/IRPrinter.java @@ -15,6 +15,7 @@ public abstract class IRPrinter { // NNID NNAME DDEF DDEF [[ UUSE UUSE ]] TYPE // 1234 sssss 1234 1234 1234 1234 1234 1234 tttttt public static SB printLine( Node n, SB sb ) { + if( n==null ) return sb; sb.p("%4d %-7.7s ".formatted(n._nid,n.label())); if( n._inputs==null ) return sb.p("DEAD\n"); diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/sontypes/SONType.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/sontypes/SONType.java index ba7eaac..86a8f70 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/sontypes/SONType.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/sontypes/SONType.java @@ -103,6 +103,7 @@ public static SONType[] gather() { // checks with every type compare, only during interning. // Factory method which interns "this" + @SuppressWarnings("unchecked") public T intern() { T nnn = (T)INTERN.get(this); if( nnn==null ) @@ -217,7 +218,7 @@ public final SONType join(SONType t) { // Sizes are expected to be between 1 and 64 bits. // Size 0 means this either takes no space (such as a known-zero field) // or isn't a scalar to be stored in memory. - public int log_size() { throw Utils.TODO(); } + public int log_size() { return 3; } // ---------------------------------------------------------- // Useful in the debugger, which calls toString everywhere. diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/sontypes/SONTypeTuple.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/sontypes/SONTypeTuple.java index f3acceb..ecb14ef 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/sontypes/SONTypeTuple.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/sontypes/SONTypeTuple.java @@ -55,6 +55,21 @@ public SONType glb() { return make(ts); } + @Override public boolean isConstant() { + for( SONType t : _types ) + if( !t.isConstant() ) + return false; + return true; + } + + @Override public int log_size() { + assert isConstant(); + int log_size = 0; + for( SONType t : _types ) + log_size = Math.max(log_size,t.log_size()); + return log_size; + } + public SONType ret() { assert _types.length==3; return _types[2]; } @Override public String str() { return print(new SB()).toString(); } diff --git a/seaofnodes/src/test/java/com/compilerprogramming/ezlang/compiler/Simple.java b/seaofnodes/src/test/java/com/compilerprogramming/ezlang/compiler/Simple.java index c649fbd..2fa8e9d 100644 --- a/seaofnodes/src/test/java/com/compilerprogramming/ezlang/compiler/Simple.java +++ b/seaofnodes/src/test/java/com/compilerprogramming/ezlang/compiler/Simple.java @@ -251,7 +251,7 @@ public static void main(String[] args) throws Exception { dump(code, dump, DUMP_AFTER_TYPE_CHECK); if (do_codegen) { - code.instSelect(PORTS, cpu, abi); + code.instSelect(cpu, abi); dump(code, dump, DUMP_AFTER_INSTR_SELECT); } diff --git a/seaofnodes/src/test/java/com/compilerprogramming/ezlang/compiler/TestSONTypes.java b/seaofnodes/src/test/java/com/compilerprogramming/ezlang/compiler/TestSONTypes.java index 78c7e87..7acfabd 100644 --- a/seaofnodes/src/test/java/com/compilerprogramming/ezlang/compiler/TestSONTypes.java +++ b/seaofnodes/src/test/java/com/compilerprogramming/ezlang/compiler/TestSONTypes.java @@ -196,7 +196,7 @@ func foo()->Int { static void testCPU( String src, String cpu, String os, int spills, String stop ) { CodeGen code = new CodeGen(src); - code.parse().opto().typeCheck().instSelect(PORTS,cpu,os).GCM().localSched().regAlloc().encode(); + code.parse().opto().typeCheck().instSelect(cpu,os).GCM().localSched().regAlloc().encode(); int delta = spills>>3; if( delta==0 ) delta = 1; assertEquals("Expect spills:",spills,code._regAlloc._spillScaled,delta);