private static string ToAMDIL(this GenericOperand operand, LiteralPool literals) { if (operand is ImmediateValue) { ImmediateValue iv = operand as ImmediateValue; string literal = literals[iv.Value]; switch (iv.Value.GetType().SizeOf()) { case 4: return literal + ".x"; case 8: return literal + ".xy"; case 16: return literal + ".xyzw"; default: throw new NotSupportedException(iv.Value.GetType().Format()); } } else return operand.ToString(); }
private static string ToAMDIL(this BasicBlockInstruction bbi, LiteralPool literals, Dictionary<string, int> functions = null, int raw_uav_id = 11, int arena_uav_id = 13) { BinaryOperation bop = bbi as BinaryOperation; UnaryOperation uop = bbi as UnaryOperation; switch (bbi.OpCode) { case IROpCodes.ADD: switch (Type.GetTypeCode(bop.Target.DataType)) { case TypeCode.Int32: case TypeCode.UInt32: return string.Format( "iadd {0}, {1}, {2}", bop.Target.ToString(), bop.LeftOperand.ToAMDIL(literals), bop.RightOperand.ToAMDIL(literals) ); case TypeCode.Int64: case TypeCode.UInt64: return string.Format( "i64add {0}, {1}, {2}", bop.Target.ToString(), bop.LeftOperand.ToAMDIL(literals), bop.RightOperand.ToAMDIL(literals) ); case TypeCode.Single: return string.Format( "add {0}, {1}, {2}", bop.Target.ToString(), bop.LeftOperand.ToAMDIL(literals), bop.RightOperand.ToAMDIL(literals) ); case TypeCode.Double: return string.Format( "dadd {0}, {1}, {2}", bop.Target.ToString(), bop.LeftOperand.ToAMDIL(literals), bop.RightOperand.ToAMDIL(literals) ); default: throw new NotSupportedException(bop.Target.DataType.Format()); } case IROpCodes.SUB: switch (Type.GetTypeCode(bop.Target.DataType)) { case TypeCode.Int32: case TypeCode.UInt32: return string.Format( "inegate r2.x, {2}\n" + "iadd {0}, {1}, r2.x", bop.Target.ToString(), bop.LeftOperand.ToAMDIL(literals), bop.RightOperand.ToAMDIL(literals) ); case TypeCode.Int64: case TypeCode.UInt64: return string.Format( "i64negate r2.xy, {2}\n" + "i64add {0}, {1}, r2.xy", bop.Target.ToString(), bop.LeftOperand.ToAMDIL(literals), bop.RightOperand.ToAMDIL(literals) ); case TypeCode.Single: return string.Format( "sub {0}, {1}, {2}", bop.Target.ToString(), bop.LeftOperand.ToAMDIL(literals), bop.RightOperand.ToAMDIL(literals) ); case TypeCode.Double: return string.Format( "dadd {0}, {1}, {2}_neg(xyzw)", bop.Target.ToString(), bop.LeftOperand.ToAMDIL(literals), bop.RightOperand.ToAMDIL(literals) ); default: throw new NotSupportedException(bop.Target.DataType.Format()); } case IROpCodes.MUL: switch (Type.GetTypeCode(bop.Target.DataType)) { case TypeCode.Int32: case TypeCode.UInt32: return string.Format( "imul {0}, {1}, {2}", bop.Target.ToString(), bop.LeftOperand.ToAMDIL(literals), bop.RightOperand.ToAMDIL(literals) ); case TypeCode.Int64: case TypeCode.UInt64: return string.Format( "i64mul {0}, {1}, {2}", bop.Target.ToString(), bop.LeftOperand.ToAMDIL(literals), bop.RightOperand.ToAMDIL(literals) ); case TypeCode.Single: return string.Format( "mul_ieee {0}, {1}, {2}", bop.Target.ToString(), bop.LeftOperand.ToAMDIL(literals), bop.RightOperand.ToAMDIL(literals) ); case TypeCode.Double: return string.Format( "dmul {0}, {1}, {2}", bop.Target.ToString(), bop.LeftOperand.ToAMDIL(literals), bop.RightOperand.ToAMDIL(literals) ); default: throw new NotSupportedException(bop.Target.DataType.Format()); } case IROpCodes.MAD: { MADOperation mad = bbi as MADOperation; switch (Type.GetTypeCode(mad.Target.DataType)) { case TypeCode.Int32: return string.Format( "imad {0}, {1}, {2}, {3}", mad.Target.ToString(), mad.MulLeftOperand.ToAMDIL(literals), mad.MulRightOperand.ToAMDIL(literals), mad.AddOperand.ToAMDIL(literals) ); case TypeCode.UInt32: return string.Format( "umad {0}, {1}, {2}, {3}", mad.Target.ToString(), mad.MulLeftOperand.ToAMDIL(literals), mad.MulRightOperand.ToAMDIL(literals), mad.AddOperand.ToAMDIL(literals) ); case TypeCode.Int64: case TypeCode.UInt64: return string.Format( "i64mul r2.xy, {1}, {2}\n" + "i64add {0}, r2.xy, {3}", mad.Target.ToString(), mad.MulLeftOperand.ToAMDIL(literals), mad.MulRightOperand.ToAMDIL(literals), mad.AddOperand.ToAMDIL(literals) ); case TypeCode.Single: return string.Format( "mad_ieee {0}, {1}, {2}, {3}", mad.Target.ToString(), mad.MulLeftOperand.ToAMDIL(literals), mad.MulRightOperand.ToAMDIL(literals), mad.AddOperand.ToAMDIL(literals) ); case TypeCode.Double: return string.Format( "dmad {0}, {1}, {2}, {3}", mad.Target.ToString(), mad.MulLeftOperand.ToAMDIL(literals), mad.MulRightOperand.ToAMDIL(literals), mad.AddOperand.ToAMDIL(literals) ); default: throw new NotSupportedException(bop.Target.DataType.Format()); } } case IROpCodes.DIV: switch (Type.GetTypeCode(bop.Target.DataType)) { case TypeCode.Int32: return string.Format( "ilt r2.x, {1}, {3}\n" + // compare left operand with 0, get -1 if negative or 0 otherwise "iadd r2.z, {1}, r2.x\n" + // r2.z = abs(left operand), see IROpCodes.ABS case "ixor r2.z, r2.z, r2.x\n" + "ilt r2.y, {2}, {3}\n" + // compare right operand with 0, get -1 if negative or 0 otherwise "iadd r2.w, {2}, r2.y\n" + // r2.w = abs(right operand), see IROpCodes.ABS case "ixor r2.w, r2.w, r2.y\n" + "udiv {0}, r2.z, r2.w\n" + // perform division with non-negative operands "ixor r2.x, r2.x, r2.y\n" + // get result sign factor (-1 if negative or 0 otherwise) "iadd {0}, {0}, r2.x\n" + // perform negation if needed "ixor {0}, {0}, r2.x", bop.Target.ToString(), bop.LeftOperand.ToAMDIL(literals), bop.RightOperand.ToAMDIL(literals), literals[(int)0] + ".x"); case TypeCode.UInt32: return string.Format( "udiv {0}, {1}, {2}", bop.Target.ToString(), bop.LeftOperand.ToAMDIL(literals), bop.RightOperand.ToAMDIL(literals) ); case TypeCode.Int64: return string.Format( "i64div {0}, {1}, {2}", bop.Target.ToString(), bop.LeftOperand.ToAMDIL(literals), bop.RightOperand.ToAMDIL(literals) ); case TypeCode.UInt64: return string.Format( "u64div {0}, {1}, {2}", bop.Target.ToString(), bop.LeftOperand.ToAMDIL(literals), bop.RightOperand.ToAMDIL(literals) ); case TypeCode.Single: return string.Format( "div_zeroop(infinity) {0}, {1}, {2}", bop.Target.ToString(), bop.LeftOperand.ToAMDIL(literals), bop.RightOperand.ToAMDIL(literals) ); case TypeCode.Double: return string.Format( "ddiv {0}, {1}, {2}", bop.Target.ToString(), bop.LeftOperand.ToAMDIL(literals), bop.RightOperand.ToAMDIL(literals) ); default: throw new NotSupportedException(bop.Target.DataType.Format()); } case IROpCodes.REM: { VirtualRegister tmp = new VirtualRegister(bop.Target.DataType) { Name = "r3" + SwizzleMask(bop.Target.ToString())}; return new BinaryOperation( IROpCodes.DIV, tmp, bop.LeftOperand, bop.RightOperand ).ToAMDIL(literals) + "\n" + new BinaryOperation( IROpCodes.MUL, tmp, tmp, bop.RightOperand ).ToAMDIL(literals) + "\n" + new BinaryOperation( IROpCodes.SUB, bop.Target, bop.LeftOperand, tmp ).ToAMDIL(literals); } case IROpCodes.MIN: case IROpCodes.MAX: switch (Type.GetTypeCode(bop.Target.DataType)) { case TypeCode.Int32: return string.Format( "i{0} {1}, {2}, {3}", bbi.OpCode.ToString().ToLower(), bop.Target.ToString(), bop.LeftOperand.ToAMDIL(literals), bop.RightOperand.ToAMDIL(literals) ); case TypeCode.UInt32: return string.Format( "u{0} {1}, {2}, {3}", bbi.OpCode.ToString().ToLower(), bop.Target.ToString(), bop.LeftOperand.ToAMDIL(literals), bop.RightOperand.ToAMDIL(literals) ); case TypeCode.Int64: return string.Format( "i64{0} {1}, {2}, {3}", bbi.OpCode.ToString().ToLower(), bop.Target.ToString(), bop.LeftOperand.ToAMDIL(literals), bop.RightOperand.ToAMDIL(literals) ); case TypeCode.UInt64: return string.Format( "u64{0} {1}, {2}, {3}", bbi.OpCode.ToString().ToLower(), bop.Target.ToString(), bop.LeftOperand.ToAMDIL(literals), bop.RightOperand.ToAMDIL(literals) ); case TypeCode.Single: return string.Format( "{0}_ieee {1}, {2}, {3}", bbi.OpCode.ToString().ToLower(), bop.Target.ToString(), bop.LeftOperand.ToAMDIL(literals), bop.RightOperand.ToAMDIL(literals) ); case TypeCode.Double: return string.Format( "d{0} {1}, {2}, {3}", bbi.OpCode.ToString().ToLower(), bop.Target.ToString(), bop.LeftOperand.ToAMDIL(literals), bop.RightOperand.ToAMDIL(literals) ); default: throw new NotSupportedException(bop.Target.DataType.Format()); } case IROpCodes.AND: case IROpCodes.OR: case IROpCodes.XOR: return string.Format( "i{0} {1}, {2}, {3}", bop.OpCode.ToString().ToLower(), bop.Target.ToString(), bop.LeftOperand.ToAMDIL(literals), bop.RightOperand.ToAMDIL(literals) ); case IROpCodes.EQ: case IROpCodes.NE: switch (Type.GetTypeCode(bop.Target.DataType)) { case TypeCode.Int32: case TypeCode.UInt32: return string.Format( "i{0} {1}, {2}, {3}", bbi.OpCode.ToString().ToLower(), bop.Target.ToString(), bop.LeftOperand.ToAMDIL(literals), bop.RightOperand.ToAMDIL(literals) ); case TypeCode.Int64: case TypeCode.UInt64: return string.Format( "i64{0} {1}, {2}, {3}", bbi.OpCode.ToString().ToLower(), bop.Target.ToString(), bop.LeftOperand.ToAMDIL(literals), bop.RightOperand.ToAMDIL(literals) ); case TypeCode.Single: return string.Format( "{0} {1}, {2}, {3}", bbi.OpCode.ToString().ToLower(), bop.Target.ToString(), bop.LeftOperand.ToAMDIL(literals), bop.RightOperand.ToAMDIL(literals) ); case TypeCode.Double: return string.Format( "d{0} {1}, {2}, {3}", bbi.OpCode.ToString().ToLower(), bop.Target.ToString(), bop.LeftOperand.ToAMDIL(literals), bop.RightOperand.ToAMDIL(literals) ); default: throw new NotSupportedException(bop.Target.DataType.Format()); } case IROpCodes.GE: case IROpCodes.LT: switch (Type.GetTypeCode(bop.Target.DataType)) { case TypeCode.Int32: return string.Format( "i{0} {1}, {2}, {3}", bbi.OpCode.ToString().ToLower(), bop.Target.ToString(), bop.LeftOperand.ToAMDIL(literals), bop.RightOperand.ToAMDIL(literals) ); case TypeCode.UInt32: return string.Format( "u{0} {1}, {2}, {3}", bbi.OpCode.ToString().ToLower(), bop.Target.ToString(), bop.LeftOperand.ToAMDIL(literals), bop.RightOperand.ToAMDIL(literals) ); case TypeCode.Int64: return string.Format( "i64{0} {1}, {2}, {3}", bbi.OpCode.ToString().ToLower(), bop.Target.ToString(), bop.LeftOperand.ToAMDIL(literals), bop.RightOperand.ToAMDIL(literals) ); case TypeCode.UInt64: return string.Format( "u64{0} {1}, {2}, {3}", bbi.OpCode.ToString().ToLower(), bop.Target.ToString(), bop.LeftOperand.ToAMDIL(literals), bop.RightOperand.ToAMDIL(literals) ); case TypeCode.Single: return string.Format( "{0} {1}, {2}, {3}", bbi.OpCode.ToString().ToLower(), bop.Target.ToString(), bop.LeftOperand.ToAMDIL(literals), bop.RightOperand.ToAMDIL(literals) ); case TypeCode.Double: return string.Format( "d{0} {1}, {2}, {3}", bbi.OpCode.ToString().ToLower(), bop.Target.ToString(), bop.LeftOperand.ToAMDIL(literals), bop.RightOperand.ToAMDIL(literals) ); default: throw new NotSupportedException(bop.Target.DataType.Format()); } case IROpCodes.GT: return new BinaryOperation( IROpCodes.LT, bop.Target, bop.RightOperand, bop.LeftOperand ).ToAMDIL(literals); case IROpCodes.LE: return new BinaryOperation( IROpCodes.GE, bop.Target, bop.RightOperand, bop.LeftOperand ).ToAMDIL(literals); case IROpCodes.NEG: switch (Type.GetTypeCode(uop.Target.DataType)) { case TypeCode.Int32: return string.Format( "inegate {0}, {1}", uop.Target.ToString(), uop.Operand.ToAMDIL(literals) ); case TypeCode.Int64: return string.Format( "i64negate {0}, {1}", uop.Target.ToString(), uop.Operand.ToAMDIL(literals) ); case TypeCode.Single: return string.Format( "mov {0}, {1}_neg(xyzw)", uop.Target.ToString(), uop.Operand.ToAMDIL(literals) ); case TypeCode.Double: return string.Format( "dadd {0}, {1}_neg(xyzw), {2}", uop.Target.ToString(), uop.Operand.ToAMDIL(literals), literals[(int)0] + ".xy" ); default: throw new NotSupportedException(bop.Target.DataType.Format()); } case IROpCodes.NOT: return string.Format( "inot {0}, {1}", uop.Target.ToString(), uop.Operand.ToAMDIL(literals) ); case IROpCodes.MOV: return string.Format( "mov {0}, {1}", uop.Target.ToString(), uop.Operand.ToAMDIL(literals) ); case IROpCodes.ABS: switch (Type.GetTypeCode(uop.Target.DataType)) { case TypeCode.Int32: return string.Format( "ishr r2.x, {1}, {2}\n" + // -1 if negative or 0 otherwise "iadd {0}, {1}, r2.x\n" + // substract 1 if negative or keep unchanged otherwise "ixor {0}, {0}, r2.x", // perform a bit-wise one's complement if negative or keep unchanged otherwise uop.Target.ToString(), uop.Operand.ToAMDIL(literals), literals[(int)31] + ".x" ); case TypeCode.Int64: return string.Format( "i64shr r2.x, {1}, {2}\n" + // -1 if negative or 0 otherwise "i64add {0}, {1}, r2.xx\n" + // substract 1 if negative or keep unchanged otherwise "ixor {0}, {0}, r2.xx", // perform a bit-wise one's complement if negative or keep unchanged otherwise uop.Target.ToString(), uop.Operand.ToAMDIL(literals), literals[(int)63] + ".x" ); case TypeCode.Single: return string.Format( "abs {0}, {1}", uop.Target.ToString(), uop.Operand.ToAMDIL(literals) ); case TypeCode.Double: return string.Format( "dadd {0}, {1}_abs, {2}", uop.Target.ToString(), uop.Operand.ToAMDIL(literals), literals[(int)0] + ".xy" ); default: throw new NotSupportedException(bop.Target.DataType.Format()); } case IROpCodes.CVT: switch (Type.GetTypeCode(uop.Target.DataType)) { case TypeCode.Int32: switch (Type.GetTypeCode(uop.Operand.DataType)) { case TypeCode.UInt32: return string.Format( "mov {0}, {1}", uop.Target.ToString(), uop.Operand.ToAMDIL(literals) ); case TypeCode.Int64: case TypeCode.UInt64: return string.Format( "mov {0}, {1}", uop.Target.ToString(), LowerPart(uop.Operand.ToAMDIL(literals)) ); case TypeCode.Single: return string.Format( "ftoi {0}, {1}", uop.Target.ToString(), uop.Operand.ToAMDIL(literals) ); case TypeCode.Double: return string.Format( "d2f {0}, {1}\n" + "ftoi {0}, {0}", uop.Target.ToString(), uop.Operand.ToAMDIL(literals)); default: throw new NotSupportedException(bop.Target.DataType.Format()); } case TypeCode.UInt32: switch (Type.GetTypeCode(uop.Operand.DataType)) { case TypeCode.Int32: return string.Format( "mov {0}, {1}", uop.Target.ToString(), uop.Operand.ToAMDIL(literals) ); case TypeCode.Int64: case TypeCode.UInt64: return string.Format( "mov {0}, {1}", uop.Target.ToString(), LowerPart(uop.Operand.ToAMDIL(literals)) ); case TypeCode.Single: return string.Format( "ftou {0}, {1}", uop.Target.ToString(), uop.Operand.ToAMDIL(literals) ); case TypeCode.Double: return string.Format( "d2f {0}, {1}\n" + "ftou {0}, {0}", uop.Target.ToString(), uop.Operand.ToAMDIL(literals)); default: throw new NotSupportedException(bop.Target.DataType.Format()); } case TypeCode.Int64: switch (Type.GetTypeCode(uop.Operand.DataType)) { case TypeCode.Int32: return string.Format( "ishr r2.y, {1}, {2}\n" + // -1 if negative or 0 otherwise "mov r2.x, {1}\n" + // perform sign extension "mov {0}, r2.xy", uop.Target.ToString(), uop.Operand.ToAMDIL(literals), literals[(int)31] + ".x" ); case TypeCode.UInt32: return string.Format( "mov {0}, {1}0", uop.Target.ToString(), uop.Operand.ToAMDIL(literals) ); case TypeCode.UInt64: return string.Format( "mov {0}, {1}", uop.Target.ToString(), uop.Operand.ToAMDIL(literals) ); case TypeCode.Single: case TypeCode.Double: default: throw new NotSupportedException(bop.Target.DataType.Format()); } case TypeCode.UInt64: switch (Type.GetTypeCode(uop.Operand.DataType)) { case TypeCode.Int32: return string.Format( "ishr r2.y, {1}, {2}\n" + // -1 if negative or 0 otherwise "mov r2.x, {1}\n" + // perform sign extension "mov {0}, r2.xy", uop.Target.ToString(), uop.Operand.ToAMDIL(literals), literals[(int)31] + ".x" ); case TypeCode.UInt32: return string.Format( "mov {0}, {1}0", uop.Target.ToString(), uop.Operand.ToAMDIL(literals) ); case TypeCode.Int64: return string.Format( "mov {0}, {1}", uop.Target.ToString(), uop.Operand.ToAMDIL(literals) ); case TypeCode.Single: case TypeCode.Double: default: throw new NotSupportedException(bop.Target.DataType.Format()); } case TypeCode.Single: switch (Type.GetTypeCode(uop.Operand.DataType)) { case TypeCode.Int32: return string.Format( "itof {0}, {1}", uop.Target.ToString(), uop.Operand.ToAMDIL(literals) ); case TypeCode.UInt32: return string.Format( "utof {0}, {1}", uop.Target.ToString(), uop.Operand.ToAMDIL(literals) ); case TypeCode.Int64: // ugly, i know!!! return string.Format( "itof {0}, {1}", uop.Target.ToString(), LowerPart(uop.Operand.ToAMDIL(literals)) ); case TypeCode.UInt64: // ugly, i know!!! return string.Format( "utof {0}, {1}", uop.Target.ToString(), LowerPart(uop.Operand.ToAMDIL(literals)) ); case TypeCode.Double: return string.Format( "d2f {0}, {1}", uop.Target.ToString(), uop.Operand.ToAMDIL(literals) ); default: throw new NotSupportedException(bop.Target.DataType.Format()); } case TypeCode.Double: switch (Type.GetTypeCode(uop.Operand.DataType)) { case TypeCode.Int32: return string.Format( "itof r2.x, {1}\n" + "f2d {0}, r2.x", uop.Target.ToString(), uop.Operand.ToAMDIL(literals)); case TypeCode.UInt32: return string.Format( "utof r2.x, {1}\n" + "f2d {0}, r2.x", uop.Target.ToString(), uop.Operand.ToAMDIL(literals)); case TypeCode.Int64: // ugly, i know!!! return string.Format( "itof r2.x, {1}\n" + "f2d {0}, r2.x", uop.Target.ToString(), LowerPart(uop.Operand.ToAMDIL(literals))); case TypeCode.UInt64: // ugly, i know!!! return string.Format( "utof r2.x, {1}\n" + "f2d {0}, r2.x", uop.Target.ToString(), LowerPart(uop.Operand.ToAMDIL(literals))); case TypeCode.Single: return string.Format( "f2d {0}, {1}", uop.Target.ToString(), uop.Operand.ToAMDIL(literals) ); default: throw new NotSupportedException(bop.Target.DataType.Format()); } default: throw new NotSupportedException(bop.Target.DataType.Format()); } case IROpCodes.LD: { LDInstruction op = bbi as LDInstruction; switch (op.Address.StateSpace) { case StateSpaces.GLOBAL: switch (Type.GetTypeCode(op.Address.UnderlyingType)) { case TypeCode.Boolean: case TypeCode.SByte: case TypeCode.Byte: return string.Format( "uav_arena_load_id({3})_size(byte)_cached {0}, {1}\n" + "ishl {0}, {0}, {2}\n" + "ishr {0}, {0}, {2}", op.Target.ToString(), op.Address.ToString(), literals[(int)24] + ".x", arena_uav_id ); case TypeCode.Int16: case TypeCode.UInt16: return string.Format( "uav_arena_load_id({3})_size(short)_cached {0}, {1}\n" + "ishl {0}, {0}, {2}\n" + "ishr {0}, {0}, {2}", op.Target.ToString(), op.Address.ToString(), literals[(int)16] + ".x", arena_uav_id ); case TypeCode.Int32: case TypeCode.UInt32: case TypeCode.Single: return string.Format( "uav_raw_load_id({2})_cached {0}, {1}", op.Target.ToString(), op.Address.ToString(), raw_uav_id ); case TypeCode.Int64: case TypeCode.UInt64: case TypeCode.Double: return string.Format( "uav_raw_load_id({2})_cached {0}, {1}", op.Target.ToString(), op.Address.ToString(), raw_uav_id ); default: throw new NotSupportedException(bop.Target.DataType.Format()); } case StateSpaces.SHARED: switch (Type.GetTypeCode(op.Address.UnderlyingType)) { case TypeCode.Boolean: case TypeCode.SByte: return string.Format( "lds_load_byte_id(1) {0}, {1}", op.Target.ToString(), op.Address.ToString() ); case TypeCode.Byte: return string.Format( "lds_load_ubyte_id(1) {0}, {1}", op.Target.ToString(), op.Address.ToString() ); case TypeCode.Int16: return string.Format( "lds_load_short_id(1) {0}, {1}", op.Target.ToString(), op.Address.ToString() ); case TypeCode.UInt16: return string.Format( "lds_load_ushort_id(1) {0}, {1}", op.Target.ToString(), op.Address.ToString() ); case TypeCode.Int32: case TypeCode.UInt32: case TypeCode.Single: return string.Format( "lds_load_id(1) {0}, {1}", op.Target.ToString(), op.Address.ToString() ); case TypeCode.Int64: case TypeCode.UInt64: case TypeCode.Double: return string.Format( "lds_load_vec_id(1) {0}, {1}, {1}", op.Target.ToString(), op.Address.ToString() ); default: throw new NotSupportedException(bop.Target.DataType.Format()); } case StateSpaces.CONSTANT: default: throw new NotImplementedException(); } } case IROpCodes.ST: { STInstruction op = bbi as STInstruction; switch (op.Address.StateSpace) { case StateSpaces.GLOBAL: switch (Type.GetTypeCode(op.Address.UnderlyingType)) { case TypeCode.Boolean: case TypeCode.SByte: case TypeCode.Byte: return string.Format( "iand {1}, {1}, {3}\n" + "uav_arena_store_id({2})_size(byte) {0}, {1}", op.Address.ToString(), op.Source.ToString(), arena_uav_id, literals[(int)255] ); case TypeCode.Int16: case TypeCode.UInt16: return string.Format( "iand {1}, {1}, {3}\n" + "uav_arena_store_id({2})_size(short) {0}, {1}", op.Address.ToString(), op.Source.ToString(), arena_uav_id, literals[(int)65535] ); case TypeCode.Int32: case TypeCode.UInt32: case TypeCode.Single: return string.Format( "uav_raw_store_id({2}) mem0.x, {0}, {1}", op.Address.ToString(), op.Source.ToString(), raw_uav_id ); case TypeCode.Int64: case TypeCode.UInt64: case TypeCode.Double: return string.Format( "uav_raw_store_id({2}) mem0.xy, {0}, {1}", op.Address.ToString(), op.Source.ToString(), raw_uav_id ); default: throw new NotSupportedException(bop.Target.DataType.Format()); } case StateSpaces.SHARED: switch (Type.GetTypeCode(op.Address.UnderlyingType)) { case TypeCode.Boolean: case TypeCode.SByte: case TypeCode.Byte: return string.Format( "lds_store_byte_id(1) {0}, {1}", op.Address.ToString(), op.Source.ToString() ); case TypeCode.Int16: case TypeCode.UInt16: return string.Format( "lds_store_short_id(1) {0}, {1}", op.Address.ToString(), op.Source.ToString() ); case TypeCode.Int32: case TypeCode.UInt32: case TypeCode.Single: return string.Format( "lds_store_id(1) {0}, {1}", op.Address.ToString(), op.Source.ToString() ); case TypeCode.Int64: case TypeCode.UInt64: case TypeCode.Double: return string.Format( "lds_store_vec_id(1) mem0.xy, {0}, {1}, {1}", op.Address.ToString(), op.Source.ToString() ); default: throw new NotSupportedException(bop.Target.DataType.Format()); } case StateSpaces.CONSTANT: default: throw new NotImplementedException(); } } case IROpCodes.SYNC: return "fence_threads_lds_memory"; case IROpCodes.SQRT: switch (Type.GetTypeCode(bop.Target.DataType)) { case TypeCode.Single: return string.Format( "sqrt_vec {0}, {1}", uop.Target.ToString(), uop.Operand.ToAMDIL(literals) ); case TypeCode.Double: return string.Format( "dsqrt {0}, {1}", uop.Target.ToString(), uop.Operand.ToAMDIL(literals) ); default: throw new NotSupportedException(bop.Target.DataType.Format()); } case IROpCodes.RSQRT: switch (Type.GetTypeCode(bop.Target.DataType)) { case TypeCode.Single: return string.Format( "rsq_vec {0}, {1}", uop.Target.ToString(), uop.Operand.ToAMDIL(literals) ); case TypeCode.Double: return string.Format( "drsq_zeroop(infinity) {0}, {1}", uop.Target.ToString(), uop.Operand.ToAMDIL(literals) ); default: throw new NotSupportedException(bop.Target.DataType.Format()); } case IROpCodes.SIN: return string.Format( "sin_vec {0}, {1}", uop.Target.ToString(), uop.Operand.ToAMDIL(literals) ); case IROpCodes.COS: return string.Format( "cos_vec {0}, {1}", uop.Target.ToString(), uop.Operand.ToAMDIL(literals) ); case IROpCodes.LG2: return string.Format( "log_vec {0}, {1}", uop.Target.ToString(), uop.Operand.ToAMDIL(literals) ); case IROpCodes.EX2: return string.Format( "exp_vec {0}, {1}", uop.Target.ToString(), uop.Operand.ToAMDIL(literals) ); case IROpCodes.CALL: { CALLInstruction call = bbi as CALLInstruction; IEnumerable<KeyValuePair<FormalParameter, GenericOperand>> argmap = call.Target.FormalParameters.Zip( call.Arguments, (fp, ap) => new KeyValuePair<FormalParameter, GenericOperand>(fp, ap) ); return string.Join( "\n", from kvp in argmap where kvp.Key.PassingStyle != PassingStyles.OUT select string.Format( "mov {0}, {1}", kvp.Key, kvp.Value ) ) + "\n" + string.Format( "call {0}", functions[call.Target.Name] ) + "\n" + string.Join( "\n", from kvp in argmap where kvp.Key.PassingStyle != PassingStyles.VAL select string.Format( "mov {1}, {0}", kvp.Key, kvp.Value ) ); } default: throw new NotSupportedException(bbi.OpCode.ToString()); } }
public static string ToAMDIL(this Program program, string kernelName, int setup_id, int func_id, int raw_uav_id, int arena_uav_id) { // Perform special registers naming. foreach (SpecialRegister sr in program.SpecialRegisters) { switch (sr.Value) { case PredefinedValues.ThreadIdxX: sr.Name = "vTidInGrp.x"; break; case PredefinedValues.ThreadIdxY: sr.Name = "vTidInGrp.y"; break; case PredefinedValues.ThreadIdxZ: sr.Name = "vTidInGrp.z"; break; case PredefinedValues.BlockDimX: sr.Name = "r0.x"; break; case PredefinedValues.BlockDimY: sr.Name = "r0.y"; break; case PredefinedValues.BlockDimZ: sr.Name = "r0.z"; break; case PredefinedValues.BlockIdxX: sr.Name = "vThreadGrpId.x"; break; case PredefinedValues.BlockIdxY: sr.Name = "vThreadGrpId.y"; break; case PredefinedValues.BlockIdxZ: sr.Name = "vThreadGrpId.z"; break; case PredefinedValues.GridDimX: sr.Name = "r1.x"; break; case PredefinedValues.GridDimY: sr.Name = "r1.y"; break; case PredefinedValues.GridDimZ: sr.Name = "r1.z"; break; default: throw new ArgumentException(string.Format("There is no \"{0}\" special register in AMDIL.", sr.Value), "program"); } } Kernel kernel = program.Kernels.Single(krn => krn.Name == kernelName); IEnumerable<Subprogram> kernelCallees = Program.GetCallsRec(kernel); // Perform register counting and naming. IEnumerable<VirtualRegister> regs = from sp in kernelCallees.Add<Subprogram>(kernel) from op in sp.LocalVariables.Concat(sp.FormalParameters) select op; int regnum = 4; foreach (VirtualRegister vr in regs) { vr.Name = "r" + (regnum++).ToString(); switch (vr.DataType.SizeOf()) { case 1: case 2: case 4: vr.Name = vr.Name + ".x"; break; case 8: vr.Name = vr.Name + ".xy"; break; case 16: vr.Name = vr.Name + ".xyzw"; break; default: throw new NotSupportedException(vr.DataType.Format()); } } Console.WriteLine("INFO: There are {0} virtual registers in AMDIL code for {1}", regnum, kernel.Name); int base_id = Math.Max(setup_id, func_id) + 1; Dictionary<string, int> functions = kernelCallees.Select( (sp, idx) => new KeyValuePair<string, int>(sp.Name, base_id + idx)).ToDictionary( kvp => kvp.Key,kvp => kvp.Value); functions.Add(kernel.Name, func_id); LiteralPool literals = new LiteralPool(); StringBuilder amdil = new StringBuilder(); amdil.AppendLine("il_cs_2_0"); amdil.AppendLine("LITERALS"); amdil.AppendLine("call " + setup_id); amdil.AppendLine("endmain"); amdil.AppendLine(); amdil.AppendLine("func " + setup_id); amdil.AppendLine("dcl_max_thread_per_group 1024"); if (kernel.FormalParameters.Any(fp => fp.StateSpace == StateSpaces.SHARED)) amdil.AppendLine("dcl_lds_id(1) 32768"); amdil.AppendLine("dcl_raw_uav_id(" + raw_uav_id + ")"); amdil.AppendLine("dcl_arena_uav_id(" + arena_uav_id + ")"); amdil.AppendLine("dcl_cb cb0[2]"); amdil.AppendLine("dcl_cb cb1[" + kernel.FormalParameters.Count + "]"); for (int i = 0; i < kernel.FormalParameters.Count(fp => fp.StateSpace == StateSpaces.CONSTANT); i++) amdil.AppendLine("dcl_cb cb" + (i + 2) + "[4096]"); amdil.AppendLine("mov r0, cb0[1].xyz0"); amdil.AppendLine("mov r1, cb0[0].xyz0"); for (int i = 0; i < kernel.FormalParameters.Count; i++) { FormalParameter fp = kernel.FormalParameters[i]; switch (fp.StateSpace) { case StateSpaces.REG: switch (Type.GetTypeCode(fp.UnderlyingType)) { case TypeCode.Boolean: case TypeCode.SByte: case TypeCode.Byte: amdil.AppendFormat( "mov {0}, cb1[{1}].x\n" + "ishl {0}, {0}, {2}\n" + "ishr {0}, {0}, {2}\n", fp.ToString(), i, literals[(int)24] + ".x" ); break; case TypeCode.Int16: case TypeCode.UInt16: amdil.AppendFormat( "mov {0}, cb1[{1}].x\n" + "ishl {0}, {0}, {2}\n" + "ishr {0}, {0}, {2}\n", fp.ToString(), i, literals[(int)16] + ".x" ); break; case TypeCode.Int32: case TypeCode.UInt32: case TypeCode.Single: amdil.AppendFormat( "mov {0}, cb1[{1}].x\n", fp.ToString(), i ); break; case TypeCode.Int64: case TypeCode.UInt64: case TypeCode.Double: amdil.AppendFormat( "mov {0}, cb1[{1}].xy\n", fp.ToString(), i ); break; default: throw new NotSupportedException(fp.UnderlyingType.Format()); } break; case StateSpaces.GLOBAL: case StateSpaces.SHARED: amdil.AppendFormat( "mov {0}, cb1[{1}].x\n", fp.ToString(), i ); break; case StateSpaces.CONSTANT: default: amdil.AppendFormat( "ixor {0}, {0}\n", fp.ToString() ); break; } } amdil.AppendLine("call " + func_id); amdil.AppendLine("ret"); amdil.AppendLine("endfunc"); amdil.AppendLine(); amdil.AppendLine(kernel.ToAMDIL(literals, functions, raw_uav_id, arena_uav_id)); foreach (Subprogram sp in kernelCallees) amdil.AppendLine(sp.ToAMDIL(literals, functions, raw_uav_id, arena_uav_id)); amdil.AppendLine("end"); amdil.AppendLine(); StringBuilder dcl_literal = new StringBuilder(); for (int i = 0; i < literals.Pool.Count; i++) { ValueType val = literals.Pool [i]; string x, y, z, w; if (val is float) { x = y = z = w = string.Format( "{0:X8}", BitConverter.ToInt32(BitConverter.GetBytes((float)val), 0) ); } else if (val is double) { y = string.Format("{0:X16}", BitConverter.DoubleToInt64Bits((double)val)); x = z = y.Substring(8); y = w = y.Substring(0, 8); } else if (val is int) { x = y = z = w = string.Format("{0:X8}", (int)val); } else throw new NotSupportedException(val.GetType().ToString()); dcl_literal.AppendFormat( "dcl_literal l{0}, 0x{1}, 0x{2}, 0x{3}, 0x{4}\n", i, x, y, z, w ); } return amdil.ToString().Replace("LITERALS", dcl_literal.ToString()); }
private static string ToAMDIL(this Subprogram subprogram, LiteralPool literals, Dictionary<string, int> functions, int raw_uav_id, int arena_uav_id) { IList<BasicBlock> bblist = subprogram.GetBasicBlocks(); StringBuilder code = new StringBuilder(); code.AppendLine("func " + functions[subprogram.Name]); try { foreach (TreeStatement st in subprogram.BuildAST()) code.AppendLine(st.ToAMDIL(literals, functions, raw_uav_id, arena_uav_id)); } catch (IrreducibleCFGException e) { Console.WriteLine("WARNING: " + subprogram.Name + " control flow will be handled with poor unsafe method"); code.AppendLine("mov r0.w, " + literals[bblist.IndexOf(subprogram.CFGRoot)] + ".w"); code.AppendLine("whileloop"); for (int i = 0; i < bblist.Count; i++) { code.AppendLine("ieq r2.x, r0.w, " + literals[i] + ".w"); code.AppendLine("if_logicalnz r2.x"); foreach (BasicBlockInstruction bbi in bblist[i].Code) code.AppendLine(bbi.ToAMDIL(literals, functions, raw_uav_id, arena_uav_id)); code.AppendLine(bblist[i].Trailer.ToAMDIL(literals, bblist)); code.AppendLine("endif"); code.AppendLine(); } code.AppendLine("endloop"); } code.AppendLine("ret"); code.AppendLine("endfunc"); return code.ToString(); }
private static string ToAMDIL( this TreeStatement src, LiteralPool literals, Dictionary<string, int> functions = null, int raw_uav_id = 11, int arena_uav_id = 13) { switch (src.StatementType) { case StatementTypes.INSTRUCTION: return (src as InstructionStatement).Instruction.ToAMDIL( literals, functions, raw_uav_id, arena_uav_id); case StatementTypes.BRANCH: { BranchStatement bs = src as BranchStatement; if (bs.TrueBranch == null) return string.Format( "if_logicalz {0}\n" + "{1}\n" + "endif", bs.Flag.ToString(), string.Join("\n", bs.FalseBranch.Select(st => st.ToAMDIL( literals, functions, raw_uav_id, arena_uav_id)))); if (bs.FalseBranch == null) return string.Format( "if_logicalnz {0}\n" + "{1}\n" + "endif", bs.Flag.ToString(), string.Join("\n", bs.TrueBranch.Select(st => st.ToAMDIL( literals, functions, raw_uav_id, arena_uav_id)))); return string.Format( "if_logicalnz {0}\n" + "{1}\n" + "else\n" + "{2}\n" + "endif", bs.Flag.ToString(), string.Join("\n", bs.TrueBranch.Select(st => st.ToAMDIL( literals, functions, raw_uav_id, arena_uav_id))), string.Join("\n", bs.FalseBranch.Select(st => st.ToAMDIL( literals, functions, raw_uav_id, arena_uav_id)))); } case StatementTypes.INFLOOP: return string.Format( "whileloop\n" + "{0}\n" + "endloop", string.Join("\n", (src as InfiniteLoopStatement).Body.Select(st => st.ToAMDIL( literals, functions, raw_uav_id, arena_uav_id)))); case StatementTypes.BREAK: return "break"; default: throw new NotSupportedException(src.StatementType.ToString()); } }
private static string ToAMDIL(this ControlFlowInstruction cfi, LiteralPool literals, IList<BasicBlock> bblist) { JumpInstruction jump = cfi as JumpInstruction; JumpIfInstruction jumpif = cfi as JumpIfInstruction; switch (cfi.OpCode) { case IROpCodes.JMP: return string.Format( "mov r0.w, {0}.w", literals[bblist.IndexOf(jump.Target)] ); case IROpCodes.JT: return string.Format( "if_logicalnz {0}\n" + "mov r0.w, {1}.w\n" + "else\n" + "mov r0.w, {2}.w\n" + "endif", jumpif.Flag.ToString(), literals[bblist.IndexOf(jumpif.Target)], literals[bblist.IndexOf(jumpif.Next)] ); case IROpCodes.JF: return string.Format( "if_logicalz {0}\n" + "mov r0.w, {1}.w\n" + "else\n" + "mov r0.w, {2}.w\n" + "endif", jumpif.Flag.ToString(), literals[bblist.IndexOf(jumpif.Target)], literals[bblist.IndexOf(jumpif.Next)] ); case IROpCodes.RET: return "ret_dyn"; default: throw new NotSupportedException(cfi.OpCode.ToString()); } }