Bug 433939: update outparams for latest Treehydra revision
authorDavid Mandelin <dmandelin@mozilla.com>
Tue, 20 May 2008 11:28:00 -0700
changeset 15139 979660ed509409e2787297780a5f5d46957e12c2
parent 15138 ce1413f5e3068d8a3f07d39b4fe6a17ed2de1e0c
child 15140 81e0ee32327a7713b3a4c8bd59ba535dc9d944ff
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs433939
milestone1.9.1a1pre
Bug 433939: update outparams for latest Treehydra revision
xpcom/analysis/liveness.js
xpcom/analysis/outparams.js
deleted file mode 100644
--- a/xpcom/analysis/liveness.js
+++ /dev/null
@@ -1,42 +0,0 @@
-/** Liveness analysis.. */
-
-function LivenessAnalysis() {
-  BackwardAnalysis.apply(this, arguments);
-}
-
-LivenessAnalysis.prototype = new BackwardAnalysis;
-
-LivenessAnalysis.prototype.flowState = function(isn, state) {
-  switch (TREE_CODE(isn)) {
-  case RETURN_EXPR:
-    let gms = TREE_OPERAND(isn, 0);
-    if (gms) {
-      // gms is usually a GIMPLE_MODIFY_STMT but can be a RESULT_DECL
-      if (TREE_CODE(gms) == GIMPLE_MODIFY_STMT) {
-        let v = GIMPLE_STMT_OPERAND(gms, 1);
-        state.add(v);
-      } else if (TREE_CODE(gms) == RESULT_DECL) {
-        // TODO figure out what really happens here
-        // Presumably we already saw the assignment to it.
-      }
-    }
-    break;
-  case GIMPLE_MODIFY_STMT:
-  case COND_EXPR:
-  case SWITCH_EXPR:
-  case CALL_EXPR:
-    for (let e in isn_defs(isn, 'strong')) {
-      if (DECL_P(e)) {
-        state.remove(e);
-      }
-    }
-    for (let e in isn_uses(isn)) {
-      if (DECL_P(e)) {
-        state.add(e);
-      }
-    }
-    break;
-  default:
-    break;
-  }
-};
--- a/xpcom/analysis/outparams.js
+++ b/xpcom/analysis/outparams.js
@@ -4,18 +4,18 @@ require({ after_gcc_pass: 'cfg' });
 include('treehydra.js');
 
 include('util.js');
 include('gcc_util.js');
 include('gcc_print.js');
 include('unstable/adts.js');
 include('unstable/analysis.js');
 include('unstable/esp.js');
+include('unstable/liveness.js');
 
-include('liveness.js');
 include('mayreturn.js');
 
 MapFactory.use_injective = true;
 
 // Print a trace for each function analyzed
 let TRACE_FUNCTIONS = 0;
 // Trace operation of the ESP analysis, use 2 or 3 for more detail
 let TRACE_ESP = 0;
@@ -78,29 +78,36 @@ function process_tree(func_decl) {
 
   let cfg = function_decl_cfg(func_decl);
 
   {
     let trace = 0;
     let b = new LivenessAnalysis(cfg, trace);
     b.run();
     for (let bb in cfg_bb_iterator(cfg)) {
-      bb.liveVarsIn = bb.stateIn;
-      bb.liveVarsOut = bb.stateOut;
+      bb.keepVars = bb.stateIn;
     }
   }
   
   let [retvar, retvars] = function() {
     let trace = 0;
     let a = new MayReturnAnalysis(cfg, trace);
     a.run();
     return [a.retvar, a.vbls];
   }();
   if (retvar == undefined && decl.resultType != 'void') throw new Error("assert");
 
+  // Make sure return value and outparams are never dropped from state.
+  for (let bb in cfg_bb_iterator(cfg)) {
+    bb.keepVars.add(retvar);
+    for each (let v in outparam_list) {
+      bb.keepVars.add(v);
+    }
+  }
+
   {
     let trace = TRACE_ESP;
     let fts = link_switches(cfg);
     let a = new OutparamCheck(cfg, psem_list, outparam_list, retvar, retvars, fts, trace);
     // This is annoying, but this field is only used for logging anyway.
     a.fndecl = func_decl;
     a.run();
     a.check(decl.resultType == 'void', func_decl);
@@ -129,17 +136,17 @@ function OutparamCheck(cfg, psem_list, o
     this.psvar_list.push(v);
   }
   if (trace) {
     print("PS vars");
     for each (let v in this.psvar_list) {
       print("    " + expr_display(v));
     }
   }
-  ESP.Analysis.call(this, cfg, this.psvar_list, av.BOTTOM, trace);
+  ESP.Analysis.call(this, cfg, this.psvar_list, av.BOTTOM, av.meet, trace);
 }
 
 // Abstract values for outparam check
 function AbstractValue(name, ch) {
   this.name = name;
   this.ch = ch;
 }
 
@@ -202,27 +209,66 @@ function makeOutparamAV(v) {
   if (cachedAVs.hasOwnProperty(key)) return cachedAVs[key];
 
   let ans = cachedAVs[key] = 
     new AbstractValue('OUTPARAM:' + expr_display(v), 'P');
   ans.outparam = v;
   return ans;
 }
 
+/** Return the integer value if this is an integer av, otherwise undefined. */
+av.intVal = function(v) {
+  if (v.hasOwnProperty('int_val'))
+    return v.int_val;
+  return undefined;
+}
+
+/** Meet function for our abstract values. */
+av.meet = function(v1, v2) {
+  // Important for following cases -- as output, undefined means top here.
+  if (v1 == undefined) v1 = av.BOTTOM;
+  if (v2 == undefined) v2 = av.BOTTOM;
+
+  // These cases apply for any lattice.
+  if (v1 == av.BOTTOM) return v2;
+  if (v2 == av.BOTTOM) return v1;
+  if (v1 == v2) return v1;
+
+  // At this point we know v1 != v2.
+  switch (v1) {
+  case av.LOCKED:
+  case av.UNLOCKED:
+    return undefined;
+  case av.ZERO:
+    return av.intVal(v2) == 0 ? v2 : undefined;
+  case av.NONZERO:
+    return av.intVal(v2) != 0 ? v2 : undefined;
+  default:
+    let iv = av.intVal(v1);
+    if (iv == 0) return v2 == av.ZERO ? v1 : undefined;
+    if (iv != undefined) return v2 == av.NONZERO ? v1 : undefined;
+    return undefined;
+  }
+}     
+
 // Outparam check analysis
 OutparamCheck.prototype = new ESP.Analysis;
 
 OutparamCheck.prototype.startValues = function() {
   let ans = create_decl_map();
   for each (let p in this.psvar_list) {
     ans.put(p, this.outparams.has(p) ? av.NOT_WRITTEN : av.BOTTOM);
   }
   return ans;
 }
 
+OutparamCheck.prototype.updateEdgeState = function(e) {
+  e.state.keepOnly(e.dest.keepVars);
+}
+
 OutparamCheck.prototype.flowState = function(isn, state) {
   switch (TREE_CODE(isn)) {
   case GIMPLE_MODIFY_STMT:
     this.processAssign(isn, state);
     break;
   case CALL_EXPR:
     this.processCall(undefined, isn, isn, state);
     break;