瀏覽代碼

added per component dce tracking

Nicolas Cannasse 8 月之前
父節點
當前提交
d7f8190eca
共有 1 個文件被更改,包括 126 次插入56 次删除
  1. 126 56
      hxsl/Dce.hx

+ 126 - 56
hxsl/Dce.hx

@@ -6,20 +6,56 @@ private class Exit {
 	}
 }
 
+private class VarRel {
+	public var v : VarDeps;
+	public var fields : Int = 0;
+	public function new(v) {
+		this.v = v;
+	}
+}
+
 private class VarDeps {
 	public var v : TVar;
-	public var keep : Bool;
-	public var used : Bool;
-	public var deps : Map<Int,VarDeps>;
-	public var adeps : Array<VarDeps>;
+	public var keep : Int = 0;
+	public var used : Int = 0;
+	public var deps : Map<Int,VarRel>;
+	public var adeps : Array<VarRel>;
 	public function new(v) {
 		this.v = v;
-		used = false;
 		deps = new Map();
 		adeps = [];
 	}
 }
 
+private class WriteTo {
+	public var vars : Array<VarDeps>;
+	public var bits : Array<Int>;
+	public function new() {
+		vars = [];
+		bits = [];
+	}
+	public function push(v,b) {
+		vars.push(v);
+		bits.push(b);
+	}
+	public function pop() {
+		vars.pop();
+		bits.pop();
+	}
+	public function append( v: VarDeps, b : Int ) {
+		for( i => v2 in vars )
+			if( v2 == v ) {
+				bits[i] |= b;
+				return;
+			}
+		push(v,b);
+	}
+	public function appendTo( w : WriteTo ) {
+		for( i => v in vars )
+			w.append(v, bits[i]);
+	}
+}
+
 class Dce {
 
 	var used : Map<Int,VarDeps>;
@@ -48,14 +84,14 @@ class Dce {
 				if( v.kind == Input )
 					inputs.push(i);
 				if( v.kind == Output || v.type.match(TBuffer(_,_,RW) | TRWTexture(_)) )
-					i.keep = true;
+					i.keep = 15;
 			}
 		}
 
 		// collect dependencies
 		for( s in shaders ) {
 			for( f in s.funs )
-				check(f.expr, [], []);
+				check(f.expr, new WriteTo(), new WriteTo());
 		}
 
 		var outExprs = [];
@@ -64,13 +100,13 @@ class Dce {
 			debug("DCE LOOP");
 
 			for( v in used )
-				if( v.keep )
-					markRec(v);
+				if( v.keep != 0 )
+					markRec(v, v.keep);
 
-			while( inputs.length > 1 && !inputs[inputs.length - 1].used )
+			while( inputs.length > 1 && inputs[inputs.length - 1].used == 0 )
 				inputs.pop();
 			for( v in inputs )
-				markRec(v);
+				markRec(v, 15);
 
 			outExprs = [];
 			for( s in shaders ) {
@@ -91,7 +127,7 @@ class Dce {
 		}
 
 		for( v in used ) {
-			if( v.used ) continue;
+			if( v.used != 0 ) continue;
 			if( v.v.kind == VarKind.Input) continue;
 			for( s in shaders )
 				s.vars.remove(v.v);
@@ -109,82 +145,116 @@ class Dce {
 		return vd;
 	}
 
-	function markRec( v : VarDeps ) {
-		if( v.used ) return;
-		debug(v.v.name+" is used");
-		v.used = true;
-		for( d in v.adeps )
-			markRec(d);
+	function swizStr( bits : Int ) {
+		if( bits == 15 )
+			return "";
+		var str = ".";
+		if( bits & 1 != 0 ) str += "x";
+		if( bits & 2 != 0 ) str += "y";
+		if( bits & 4 != 0 ) str += "z";
+		if( bits & 8 != 0 ) str += "w";
+		return str;
 	}
 
-	function link( v : TVar, writeTo : Array<VarDeps> ) {
+	function markRec( v : VarDeps, bits : Int ) {
+		if( v.used & bits == bits ) return;
+		bits &= ~v.used;
+		debug(v.v.name+swizStr(bits)+" is used");
+		v.used |= bits;
+		for( d in v.adeps ) {
+			var mask = makeFieldsBits(15, bits);
+			if( d.fields & mask != 0 )
+				markRec(d.v, extractFieldsBits(d.fields,bits));
+		}
+	}
+
+	function extractFieldsBits( fields : Int, write : Int ) {
+		return ((write & 1 == 0 ? 0 : fields) | (write & 2 == 0 ? 0 : fields>>4) | (write & 4 == 0 ? 0 : fields>>8) | (write & 8 == 0 ? 0 : fields>>12)) & 15;
+	}
+
+	function makeFieldsBits( read : Int, write : Int ) {
+		return write * ((read & 1) + ((read & 2) << 3) + ((read & 4) << 6) + ((read & 8) << 9));
+	}
+
+	function link( v : TVar, writeTo : WriteTo, bits = 15 ) {
 		var vd = get(v);
-		for( w in writeTo ) {
+		for( i => w in writeTo.vars ) {
 			if( w == null ) {
 				// mark for conditional
-				if( !vd.keep ) {
+				if( vd.keep == 0 ) {
 					debug("Force keep "+vd.v.name);
-					vd.keep = true;
+					vd.keep = 15;
 					markAsKeep = true;
 				}
 				continue;
 			}
-			if( !w.deps.exists(v.id) ) {
-				debug(w.v.name+" depends on "+vd.v.name);
-				w.deps.set(v.id, vd);
-				w.adeps.push(vd);
+			var d = w.deps.get(v.id);
+			if( d == null ) {
+				d = new VarRel(vd);
+				w.deps.set(v.id, d);
+				w.adeps.push(d);
+			}
+			var fields = makeFieldsBits(bits, writeTo.bits[i]);
+			if( d.fields & fields != fields ) {
+				d.fields |= fields;
+				debug(w.v.name+swizStr(writeTo.bits[i])+" depends on "+vd.v.name+swizStr(bits));
 			}
 		}
 	}
 
-	function check( e : TExpr, writeTo : Array<VarDeps>, isAffected : Array<VarDeps> ) : Void {
+	function swizBits( sw : Array<Component> ) {
+		var b = 0;
+		for( c in sw )
+			b |= 1 << c.getIndex();
+		return b;
+	}
+
+	function check( e : TExpr, writeTo : WriteTo, isAffected : WriteTo ) : Void {
 		switch( e.e ) {
 		case TVar(v):
 			link(v, writeTo);
-		case TBinop(OpAssign | OpAssignOp(_), { e : (TVar(v) | TSwiz( { e : TVar(v) }, _)) }, e):
+		case TSwiz({ e : TVar(v) }, swiz):
+			link(v, writeTo, swizBits(swiz));
+		case TBinop(OpAssign | OpAssignOp(_), { e : TVar(v) }, e):
 			var v = get(v);
-			writeTo.push(v);
+			writeTo.push(v,15);
 			check(e, writeTo, isAffected);
 			writeTo.pop();
-			if( isAffected.indexOf(v) < 0 )
-				isAffected.push(v);
+			isAffected.append(v,15);
+		case TBinop(OpAssign | OpAssignOp(_), { e : TSwiz({ e : TVar(v) },swiz) }, e):
+			var v = get(v);
+			var bits = swizBits(swiz);
+			writeTo.push(v,bits);
+			check(e, writeTo, isAffected);
+			writeTo.pop();
+			isAffected.append(v,bits);
 		case TBinop(OpAssign | OpAssignOp(_), { e : (TArray({ e: TVar(v) }, i) | TSwiz({ e : TArray({ e : TVar(v) }, i) },_) | TField({e : TArray({ e : TVar(v) }, i) }, _)) }, e):
 			var v = get(v);
-			writeTo.push(v);
+			writeTo.push(v,15);
 			check(i, writeTo, isAffected);
 			check(e, writeTo, isAffected);
 			writeTo.pop();
-			if( isAffected.indexOf(v) < 0 )
-				isAffected.push(v);
+			isAffected.append(v,15);
 		case TBlock(el):
-			var noWrite = [];
+			var noWrite = new WriteTo();
 			for( i in 0...el.length )
 				check(el[i],i < el.length - 1 ? noWrite : writeTo, isAffected);
 		case TVarDecl(v, init) if( init != null ):
-			writeTo.push(get(v));
+			writeTo.push(get(v),15);
 			check(init, writeTo, isAffected);
 			writeTo.pop();
 		case TIf(e, eif, eelse):
-			var affect = [];
+			var affect = new WriteTo();
 			check(eif, writeTo, affect);
 			if( eelse != null ) check(eelse, writeTo, affect);
-			var len = affect.length;
-			for( v in writeTo )
-				if( affect.indexOf(v) < 0 )
-					affect.push(v);
+			affect.appendTo(isAffected);
+			writeTo.appendTo(affect);
 			check(e, affect, isAffected);
-			for( i in 0...len ) {
-				var v = affect[i];
-				if( isAffected.indexOf(v) < 0 )
-					isAffected.push(v);
-			}
 		case TFor(v, it, loop):
-			var affect = [];
+			var affect = new WriteTo();
 			check(loop, writeTo, affect);
+			affect.appendTo(isAffected);
 			check(it, affect, isAffected);
-			for( v in affect )
-				if( isAffected.indexOf(v) < 0 )
-					isAffected.push(v);
 		case TCall({ e : TGlobal(ChannelRead) }, [{ e : TVar(c) }, uv, { e : TConst(CInt(cid)) }]):
 			check(uv, writeTo, isAffected);
 			if( channelVars[cid] == null ) {
@@ -204,12 +274,11 @@ class Dce {
 			}
 		case TCall({ e : TGlobal(ImageStore)}, [{ e : TVar(v) }, uv, val]):
 			var v = get(v);
-			writeTo.push(v);
+			writeTo.push(v,15);
 			check(uv, writeTo, isAffected);
 			check(val, writeTo, isAffected);
 			writeTo.pop();
-			if( isAffected.indexOf(v) < 0 )
-				isAffected.push(v);
+			isAffected.append(v,15);
 		default:
 			e.iter(check.bind(_, writeTo, isAffected));
 		}
@@ -219,8 +288,9 @@ class Dce {
 		// found a branch with side effect left, this condition vars needs to be kept
 		switch( e.e ) {
 		case TIf(cond, _, _):
-			var writeTo = [null];
-			check(cond, writeTo, []);
+			var writeTo = new WriteTo();
+			writeTo.append(null,0);
+			check(cond, writeTo, new WriteTo());
 		default:
 		}
 		e.iter(checkBranches);
@@ -239,7 +309,7 @@ class Dce {
 				count++;
 			}
 			return { e : TBlock(out), p : e.p, t : e.t };
-		case TVarDecl(v,_) | TBinop(OpAssign | OpAssignOp(_), { e : (TVar(v) | TSwiz( { e : TVar(v) }, _) | TArray( { e : TVar(v) }, _)) }, _) if( !get(v).used ):
+		case TVarDecl(v,_) | TBinop(OpAssign | OpAssignOp(_), { e : (TVar(v) | TSwiz( { e : TVar(v) }, _) | TArray( { e : TVar(v) }, _)) }, _) if( get(v).used == 0 ):
 			return { e : TConst(CNull), t : e.t, p : e.p };
 		case TCall({ e : TGlobal(ChannelRead) }, [_, uv, { e : TConst(CInt(cid)) }]):
 			var c = channelVars[cid];