aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Lattner <sabre@nondot.org>2001-07-20 19:17:55 +0000
committerChris Lattner <sabre@nondot.org>2001-07-20 19:17:55 +0000
commit369bbeb62cef986b6eb5213c9edab1a4c4f157af (patch)
treed209228e4798fba56ae37d77769f70d81b320a94
parentba7cf16dbb6225d487abc602b3464db0a8b16387 (diff)
downloadexternal_llvm-369bbeb62cef986b6eb5213c9edab1a4c4f157af.zip
external_llvm-369bbeb62cef986b6eb5213c9edab1a4c4f157af.tar.gz
external_llvm-369bbeb62cef986b6eb5213c9edab1a4c4f157af.tar.bz2
Start of expression analysis support
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@219 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/llvm/Analysis/Expressions.h60
-rw-r--r--lib/Analysis/Expressions.cpp207
2 files changed, 267 insertions, 0 deletions
diff --git a/include/llvm/Analysis/Expressions.h b/include/llvm/Analysis/Expressions.h
new file mode 100644
index 0000000..c21599f
--- /dev/null
+++ b/include/llvm/Analysis/Expressions.h
@@ -0,0 +1,60 @@
+//===- llvm/Analysis/Expressions.h - Expression Analysis Utils ---*- C++ -*--=//
+//
+// This file defines a package of expression analysis utilties:
+//
+// ClassifyExpression: Analyze an expression to determine the complexity of the
+// expression, and which other variables it depends on.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ANALYSIS_EXPRESSIONS_H
+#define LLVM_ANALYSIS_EXPRESSIONS_H
+
+#include <assert.h>
+class Value;
+class ConstPoolInt;
+struct ExprAnalysisResult;
+
+// ClassifyExpression: Analyze an expression to determine the complexity of the
+// expression, and which other values it depends on.
+//
+ExprAnalysisResult ClassifyExpression(Value *Expr);
+
+// ExprAnalysisResult - Represent an expression of the form CONST*VAR+CONST
+// or simpler. The expression form that yields the least information about the
+// expression is just the Linear form with no offset.
+//
+struct ExprAnalysisResult {
+ enum ExpressionType {
+ Constant, // Expr is a simple constant, Offset is value
+ Linear, // Expr is linear expr, Value is Var+Offset
+ ScaledLinear, // Expr is scaled linear exp, Value is Scale*Var+Offset
+ } ExprType;
+
+ const ConstPoolInt *Offset; // Offset of expr, or null if 0
+ Value *Var; // Var referenced, if Linear or above (null if 0)
+ const ConstPoolInt *Scale; // Scale of var if ScaledLinear expr (null if 1)
+
+ inline ExprAnalysisResult(const ConstPoolInt *CPV = 0) {
+ Offset = CPV; Var = 0; Scale = 0;
+ ExprType = Constant;
+ }
+ inline ExprAnalysisResult(Value *Val) {
+ Var = Val; Offset = Scale = 0;
+ ExprType = Var ? Linear : Constant;
+ }
+ inline ExprAnalysisResult(const ConstPoolInt *scale, Value *var,
+ const ConstPoolInt *offset) {
+ assert(!(Scale && !Var) && "Can't have scaled nonvariable!");
+ Scale = scale; Var = var; Offset = offset;
+ ExprType = Scale ? ScaledLinear : (Var ? Linear : Constant);
+ }
+
+
+private:
+ friend ExprAnalysisResult ClassifyExpression(Value *);
+ inline ExprAnalysisResult operator+(const ConstPoolInt *Offset);
+
+};
+
+#endif
diff --git a/lib/Analysis/Expressions.cpp b/lib/Analysis/Expressions.cpp
new file mode 100644
index 0000000..ac6bdc1
--- /dev/null
+++ b/lib/Analysis/Expressions.cpp
@@ -0,0 +1,207 @@
+//===- Expressions.cpp - Expression Analysis Utilities ----------------------=//
+//
+// This file defines a package of expression analysis utilties:
+//
+// ClassifyExpression: Analyze an expression to determine the complexity of the
+// expression, and which other variables it depends on.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Analysis/Expressions.h"
+#include "llvm/Optimizations/ConstantHandling.h"
+#include "llvm/ConstantPool.h"
+#include "llvm/Method.h"
+#include "llvm/BasicBlock.h"
+
+using namespace opt; // Get all the constant handling stuff
+
+// getIntegralConstant - Wrapper around the ConstPoolInt member of the same
+// name. This method first checks to see if the desired constant is already in
+// the constant pool. If it is, it is quickly recycled, otherwise a new one
+// is allocated and added to the constant pool.
+//
+static ConstPoolInt *getIntegralConstant(ConstantPool &CP, unsigned char V,
+ const Type *Ty) {
+ // FIXME: Lookup prexisting constant in table!
+
+ ConstPoolInt *CPI = ConstPoolInt::get(Ty, V);
+ CP.insert(CPI);
+ return CPI;
+}
+
+static ConstPoolUInt *getUnsignedConstant(ConstantPool &CP, uint64_t V) {
+ // FIXME: Lookup prexisting constant in table!
+
+ ConstPoolUInt *CPUI = new ConstPoolUInt(Type::ULongTy, V);
+ CP.insert(CPUI);
+ return CPUI;
+}
+
+
+// Add - Helper function to make later code simpler. Basically it just adds
+// the two constants together, inserts the result into the constant pool, and
+// returns it. Of course life is not simple, and this is no exception. Factors
+// that complicate matters:
+// 1. Either argument may be null. If this is the case, the null argument is
+// treated as either 0 (if DefOne = false) or 1 (if DefOne = true)
+// 2. Types get in the way. We want to do arithmetic operations without
+// regard for the underlying types. It is assumed that the constants are
+// integral constants. The new value takes the type of the left argument.
+// 3. If DefOne is true, a null return value indicates a value of 1, if DefOne
+// is false, a null return value indicates a value of 0.
+//
+inline const ConstPoolInt *Add(ConstantPool &CP, const ConstPoolInt *Arg1,
+ const ConstPoolInt *Arg2, bool DefOne = false) {
+ if (DefOne == false) { // Handle degenerate cases first...
+ if (Arg1 == 0) return Arg2; // Also handles case of Arg1 == Arg2 == 0
+ if (Arg2 == 0) return Arg1;
+ } else { // These aren't degenerate... :(
+ if (Arg1 == 0 && Arg2 == 0) return getIntegralConstant(CP, 2, Type::UIntTy);
+ if (Arg1 == 0) Arg1 = getIntegralConstant(CP, 1, Arg2->getType());
+ if (Arg2 == 0) Arg2 = getIntegralConstant(CP, 1, Arg2->getType());
+ }
+
+ assert(Arg1 && Arg2 && "No null arguments should exist now!");
+
+ // FIXME: Make types compatible!
+
+ // Actually perform the computation now!
+ ConstPoolVal *Result = *Arg1 + *Arg2;
+ assert(Result && Result->getType()->isIntegral() && "Couldn't perform add!");
+ ConstPoolInt *ResultI = (ConstPoolInt*)Result;
+
+ // Check to see if the result is one of the special cases that we want to
+ // recognize...
+ if (ResultI->equals(DefOne ? 1 : 0)) {
+ // Yes it is, simply delete the constant and return null.
+ delete ResultI;
+ return 0;
+ }
+
+ CP.insert(ResultI);
+ return ResultI;
+}
+
+
+ExprAnalysisResult ExprAnalysisResult::operator+(const ConstPoolInt *NewOff) {
+ if (NewOff == 0) return *this; // No change!
+
+ ConstantPool &CP = (ConstantPool&)NewOff->getParent()->getConstantPool();
+ return ExprAnalysisResult(Scale, Var, Add(CP, Offset, NewOff));
+}
+
+
+// Mult - Helper function to make later code simpler. Basically it just
+// multiplies the two constants together, inserts the result into the constant
+// pool, and returns it. Of course life is not simple, and this is no
+// exception. Factors that complicate matters:
+// 1. Either argument may be null. If this is the case, the null argument is
+// treated as either 0 (if DefOne = false) or 1 (if DefOne = true)
+// 2. Types get in the way. We want to do arithmetic operations without
+// regard for the underlying types. It is assumed that the constants are
+// integral constants.
+// 3. If DefOne is true, a null return value indicates a value of 1, if DefOne
+// is false, a null return value indicates a value of 0.
+//
+inline const ConstPoolInt *Mult(ConstantPool &CP, const ConstPoolInt *Arg1,
+ const ConstPoolInt *Arg2, bool DefOne = false) {
+ if (DefOne == false) { // Handle degenerate cases first...
+ if (Arg1 == 0 || Arg2 == 0) return 0; // 0 * x == 0
+ } else { // These aren't degenerate... :(
+ if (Arg1 == 0) return Arg2; // Also handles case of Arg1 == Arg2 == 0
+ if (Arg2 == 0) return Arg1;
+ }
+ assert(Arg1 && Arg2 && "No null arguments should exist now!");
+
+ // FIXME: Make types compatible!
+
+ // Actually perform the computation now!
+ ConstPoolVal *Result = *Arg1 * *Arg2;
+ assert(Result && Result->getType()->isIntegral() && "Couldn't perform mult!");
+ ConstPoolInt *ResultI = (ConstPoolInt*)Result;
+
+ // Check to see if the result is one of the special cases that we want to
+ // recognize...
+ if (ResultI->equals(DefOne ? 1 : 0)) {
+ // Yes it is, simply delete the constant and return null.
+ delete ResultI;
+ return 0;
+ }
+
+ CP.insert(ResultI);
+ return ResultI;
+}
+
+
+// ClassifyExpression: Analyze an expression to determine the complexity of the
+// expression, and which other values it depends on.
+//
+// Note that this analysis cannot get into infinite loops because it treats PHI
+// nodes as being an unknown linear expression.
+//
+ExprAnalysisResult ClassifyExpression(Value *Expr) {
+ assert(Expr != 0 && "Can't classify a null expression!");
+ switch (Expr->getValueType()) {
+ case Value::InstructionVal: break; // Instruction... hmmm... investigate.
+ case Value::TypeVal: case Value::BasicBlockVal:
+ case Value::MethodVal: case Value::ModuleVal:
+ assert(0 && "Unexpected expression type to classify!");
+ case Value::MethodArgumentVal: // Method arg: nothing known, return var
+ return Expr;
+ case Value::ConstantVal: // Constant value, just return constant
+ ConstPoolVal *CPV = Expr->castConstantAsserting();
+ if (CPV->getType()->isIntegral()) { // It's an integral constant!
+ ConstPoolInt *CPI = (ConstPoolInt*)Expr;
+ return ExprAnalysisResult(CPI->equals(0) ? 0 : (ConstPoolInt*)Expr);
+ }
+ return Expr;
+ }
+
+ Instruction *I = Expr->castInstructionAsserting();
+ ConstantPool &CP = I->getParent()->getParent()->getConstantPool();
+
+ switch (I->getOpcode()) { // Handle each instruction type seperately
+ case Instruction::Add: {
+ ExprAnalysisResult LeftTy (ClassifyExpression(I->getOperand(0)));
+ ExprAnalysisResult RightTy(ClassifyExpression(I->getOperand(1)));
+ if (LeftTy.ExprType > RightTy.ExprType)
+ swap(LeftTy, RightTy); // Make left be simpler than right
+
+ switch (LeftTy.ExprType) {
+ case ExprAnalysisResult::Constant:
+ return RightTy + LeftTy.Offset;
+ case ExprAnalysisResult::Linear: // RHS side must be linear or scaled
+ case ExprAnalysisResult::ScaledLinear: // RHS must be scaled
+ if (LeftTy.Var != RightTy.Var) // Are they the same variables?
+ return ExprAnalysisResult(I); // if not, we don't know anything!
+
+ const ConstPoolInt *NewScale = Add(CP, LeftTy.Scale, RightTy.Scale,true);
+ const ConstPoolInt *NewOffset = Add(CP, LeftTy.Offset, RightTy.Offset);
+ return ExprAnalysisResult(NewScale, LeftTy.Var, NewOffset);
+ }
+ } // end case Instruction::Add
+
+ case Instruction::Shl: {
+ ExprAnalysisResult RightTy(ClassifyExpression(I->getOperand(1)));
+ if (RightTy.ExprType != ExprAnalysisResult::Constant)
+ break; // TODO: Can get some info if it's (<unsigned> X + <offset>)
+
+ ExprAnalysisResult LeftTy (ClassifyExpression(I->getOperand(0)));
+ if (RightTy.Offset == 0) return LeftTy; // shl x, 0 = x
+ assert(RightTy.Offset->getType() == Type::UByteTy &&
+ "Shift amount must always be a unsigned byte!");
+ uint64_t ShiftAmount = ((ConstPoolUInt*)RightTy.Offset)->getValue();
+ ConstPoolUInt *Multiplier = getUnsignedConstant(CP, 1ULL << ShiftAmount);
+
+ return ExprAnalysisResult(Mult(CP, LeftTy.Scale, Multiplier, true),
+ LeftTy.Var,
+ Mult(CP, LeftTy.Offset, Multiplier));
+ } // end case Instruction::Shl
+
+ // TODO: Handle CAST, SUB, MULT (at least!)
+
+ } // end switch
+
+ // Otherwise, I don't know anything about this value!
+ return ExprAnalysisResult(I);
+}