m3front/src/exprs/ModExpr.m3


 Copyright (C) 1992, Digital Equipment Corporation           
 All rights reserved.                                        
 See the file COPYRIGHT for a full description.              
                                                             
 File: ModExpr.m3                                            
 Last modified on Thu Dec 15 14:01:22 PST 1994 by kalsow     
      modified on Thu Nov 29 03:31:49 1990 by muller         

MODULE ModExpr;

IMPORT CG, Expr, ExprRep, Type, Int, LInt, IntegerExpr, Target;
IMPORT Reel, LReel, EReel, ReelExpr, DivExpr, TInt;

TYPE
  Class = { cINT, cLINT, cREAL, cLONG, cEXTND, cERR };

CONST
  CGType = ARRAY [Class.cREAL .. Class.cEXTND] OF CG.Type {
             CG.Type.Reel, CG.Type.LReel, CG.Type.XReel};

TYPE
  P = ExprRep.Tab BRANDED "ModExpr.P" OBJECT
        class: Class;
        tmp1 : CG.Var;
        tmp2 : CG.Var;
      OVERRIDES
        typeOf       := ExprRep.NoType;
        check        := Check;
        need_addr    := ExprRep.NotAddressable;
        prep         := Prep;
        compile      := Compile;
        prepLV       := ExprRep.NotLValue;
        compileLV    := ExprRep.NotLValue;
        prepBR       := ExprRep.NotBoolean;
        compileBR    := ExprRep.NotBoolean;
        evaluate     := Fold;
        isEqual      := ExprRep.EqCheckAB;
        getBounds    := GetBounds;
        isWritable   := ExprRep.IsNever;
        isDesignator := ExprRep.IsNever;
        isZeroes     := ExprRep.IsNever;
        genFPLiteral := ExprRep.NoFPLiteral;
        prepLiteral  := ExprRep.NoPrepLiteral;
        genLiteral   := ExprRep.NoLiteral;
        note_write   := ExprRep.NotWritable;
      END;

PROCEDURE New (a, b: Expr.T): Expr.T =
  VAR p: P;
  BEGIN
    p := NEW (P);
    ExprRep.Init (p);
    p.a    := a;
    p.b    := b;
    p.type := Int.T;
    p.tmp1 := NIL;
    p.tmp2 := NIL;
    RETURN p;
  END New;

PROCEDURE Check (p: P;  VAR cs: Expr.CheckState) =
  VAR ta, tb: Type.T;
  BEGIN
    Expr.TypeCheck (p.a, cs);
    Expr.TypeCheck (p.b, cs);
    ta := Type.Base (Expr.TypeOf (p.a));
    tb := Type.Base (Expr.TypeOf (p.b));
    IF    (ta = Int.T)   AND (tb = Int.T)   THEN
      p.class := Class.cINT;
    ELSIF (ta = LInt.T)  AND (tb = LInt.T)  THEN
      p.class := Class.cLINT;
    ELSIF (ta = Reel.T)  AND (tb = Reel.T)  THEN
      p.class := Class.cREAL;
    ELSIF (ta = LReel.T) AND (tb = LReel.T) THEN
      p.class := Class.cLONG;
    ELSIF (ta = EReel.T) AND (tb = EReel.T) THEN
      p.class := Class.cEXTND;
    ELSE p.class := Class.cERR;  ta := Int.T;
      ta := Expr.BadOperands ("MOD", ta, tb);
    END;
    p.type := ta;
  END Check;

PROCEDURE Prep (p: P) =
  VAR cg_type: CG.Type;  sz, align: INTEGER;  info: Type.Info;
  BEGIN
    Expr.Prep (p.a);
    Expr.Prep (p.b);
    IF (p.class # Class.cINT) AND (p.class # Class.cLINT) THEN
      (* floating point: x MOD y == x - y * FLOOR (x / y)  *)
      EVAL Type.CheckInfo (p.a.type, info);
      sz := info.size;
      align := info.alignment;
      cg_type := CGType [p.class];

      Expr.Compile (p.a);
      p.tmp1 := CG.Declare_temp (sz, align, cg_type, in_memory := FALSE);
      CG.Store (p.tmp1, 0, sz, align, cg_type);

      Expr.Compile (p.b);
      p.tmp2 := CG.Declare_temp (sz, align, cg_type, in_memory := FALSE);
      CG.Store (p.tmp2, 0, sz, align, cg_type);
    END;
  END Prep;

PROCEDURE Compile (p: P) =
  VAR
    cg_type: CG.Type;
    info: Type.Info;
    sz, align: INTEGER;
    e1, e2, e3: Expr.T;
    divisor, mask: Target.Int;
    log: INTEGER;
    t: Type.T;
  BEGIN
    IF (p.class = Class.cINT) OR (p.class = Class.cLINT) THEN
      cg_type := Type.CGType (p.type);
      e1 := Expr.ConstValue (p.a);
      e2 := Expr.ConstValue (p.b);
      e3 := NIL;
      IF (e1 # NIL) AND (e2 # NIL) AND IntegerExpr.Mod (e1, e2, e3) THEN
        Expr.Compile (e3);
      ELSIF (e2 # NIL)
        AND IntegerExpr.Split (e2, divisor, t)
        AND DivExpr.SmallPowerOfTwo (divisor, log) THEN
        IF (e1 = NIL) THEN e1 := p.a; END;
        IF (log = 0) THEN
          (* mod 1 => zero *)
          Expr.Compile (e1);
          CG.Discard (cg_type);
          CG.Load_integer (cg_type, TInt.Zero);
        ELSE
          EVAL TInt.Subtract (divisor, TInt.One, mask);
          Expr.Compile (e1);
          CG.Load_integer (cg_type, mask);
          CG.And (cg_type);
        END;
      ELSE
        IF (e1 = NIL) THEN e1 := p.a; END;
        IF (e2 = NIL) THEN e2 := p.b; END;
        Expr.Compile (e1);
        Expr.Compile (e2);
        CG.Mod (cg_type, Expr.GetSign (e1), Expr.GetSign (e2));
      END;
    ELSE
      (* floating point: x MOD y == x - y * FLOOR (x / y)  *)
      EVAL Type.CheckInfo (p.a.type, info);
      sz := info.size;
      align := info.alignment;
      cg_type := CGType [p.class];

      CG.Load (p.tmp1, 0, sz, align, cg_type);
      CG.Load (p.tmp2, 0, sz, align, cg_type);
      CG.Divide (cg_type);
      CG.Cvt_int (cg_type, Target.Integer.cg_type, CG.Cvt.Floor);
      CG.Cvt_float (Target.Integer.cg_type, cg_type);
      CG.Load (p.tmp2, 0, sz, align, cg_type);
      CG.Multiply (cg_type);
      CG.Load (p.tmp1, 0, sz, align, cg_type);
      CG.Swap ();
      CG.Subtract (cg_type);

      CG.Free_temp (p.tmp1);
      CG.Free_temp (p.tmp2);
      p.tmp1 := NIL;
      p.tmp2 := NIL;
    END;
  END Compile;

PROCEDURE Fold (p: P): Expr.T =
  VAR e1, e2, e3: Expr.T;
  BEGIN
    e1 := Expr.ConstValue (p.a);
    e2 := Expr.ConstValue (p.b);
    e3 := NIL;
    IF    (e1 = NIL) OR (e2 = NIL)     THEN
    ELSIF IntegerExpr.Mod (e1, e2, e3) THEN
    ELSIF ReelExpr.Mod    (e1, e2, e3) THEN
    END;
    RETURN e3;
  END Fold;

PROCEDURE GetBounds (p: P;  VAR min, max: Target.Int) =
  VAR min_b, max_b: Target.Int;
      OneI := Target.Int{Target.Integer.bytes, Target.IBytes{1,0,..}};
      OneL := Target.Int{Target.Longint.bytes, Target.IBytes{1,0,..}};
      One := ARRAY[Class.cINT..Class.cLINT] OF Target.Int { OneI, OneL };
      MaxI := Target.Integer.max;
      MaxL := Target.Longint.max;
      Max := ARRAY [Class.cINT..Class.cLINT] OF Target.Int { MaxI, MaxL };
  BEGIN
    IF (p.class = Class.cINT) OR (p.class = Class.cLINT) THEN
      Expr.GetBounds (p.b, min_b, max_b);
      IF TInt.LT (min_b, TInt.Zero) OR TInt.LT (max_b, TInt.Zero) THEN
        ExprRep.NoBounds (p, min, max);
      ELSE
        min := TInt.Zero;
        IF NOT TInt.Subtract (max_b, One[p.class], max) THEN
          max := Max[p.class];
        END;
      END;
    ELSE
      ExprRep.NoBounds (p, min, max);
    END;
  END GetBounds;

BEGIN
END ModExpr.

interface Type is in: