File: CastExpr.m3 Last Modified On Tue May 23 15:33:47 PDT 1995 By kalsow Modified On Sun Dec 23 08:07:22 1990 By muller
MODULE; IMPORT M3Buf, CG, Expr, ExprRep, Type, Error, OpenArrayType; IMPORT M3, M3ID, M3RT, Target, TInt; FROM Target IMPORT FloatType; TYPE Kind = { Noop, (* code generator cannot tell the difference *) D_to_A, (* designator -> open array *) S_to_A, (* structure -> open array *) V_to_A, (* value -> open array *) D_to_S, (* designator -> structure *) S_to_S, (* structure -> structure *) V_to_S, (* value -> structure *) D_to_V, (* designator -> value *) S_to_V, (* structure -> value *) V_to_V (* value -> value *) }; TYPE P = Expr.T BRANDED "CastExpr" OBJECT kind : Kind; expr : Expr.T; tipe : Type.T; tmp : CG.Var; tmp_cnt : INTEGER; OVERRIDES typeOf := ExprRep.NoType; check := Check; need_addr := NeedsAddress; prep := Prep; compile := Compile; prepLV := PrepLV; compileLV := CompileLV; prepBR := ExprRep.PrepNoBranch; compileBR := ExprRep.NoBranch; evaluate := Fold; isEqual := EqCheck; getBounds := Bounder; isWritable := IsWritable; isDesignator := IsDesignator; isZeroes := ExprRep.IsNever; genFPLiteral := GenFPLiteral; prepLiteral := ExprRep.NoPrepLiteral; genLiteral := ExprRep.NoLiteral; note_write := NoteWrites; END; PROCEDURE CastExpr New (a: Expr.T; t: Type.T): Expr.T = VAR p: P; BEGIN p := NEW (P); ExprRep.Init (p); p.origin := a.origin; p.expr := a; p.tipe := t; p.type := t; p.tmp := NIL; p.tmp_cnt:= 0; RETURN p; END New; PROCEDURECheck (p: P; VAR cs: Expr.CheckState) = VAR src, dest, elt: Type.T; sz0, sz1: INTEGER; array_out, desig_in, struct_in, struct_out: BOOLEAN; align_in, align_out: INTEGER; dest_info, src_info, elt_info: Type.Info; BEGIN Expr.TypeCheck (p.expr, cs); p.tipe := Type.CheckInfo (p.tipe, dest_info); src := Type.CheckInfo (Expr.TypeOf (p.expr), src_info); dest := p.tipe; desig_in := Expr.IsDesignator (p.expr); struct_in := Type.IsStructured (src); struct_out := Type.IsStructured (dest); array_out := OpenArrayType.Split (dest, elt); align_in := src_info.alignment; align_out := dest_info.alignment; (* check to see that the value is legal *) IF (src_info.class = Type.Class.OpenArray) THEN Error.Msg ("LOOPHOLE: first argument cannot be an open array"); END; sz0 := src_info.size; (* check to see that the destination type is legal *) IF array_out THEN (* open array type *) elt := Type.CheckInfo (elt, elt_info); IF (elt_info.class = Type.Class.OpenArray) THEN Error.Msg ("LOOPHOLE: multidimensional open arrays not supported"); END; sz1 := elt_info.size; IF (sz1 <= 0) OR ((sz0 MOD sz1) # 0) THEN Error.Msg ("LOOPHOLE: expression's size incompatible with type's"); END; align_out := elt_info.alignment; ELSE (* fixed size type *) sz1 := dest_info.size; IF (sz0 # sz1) THEN Error.Msg ("LOOPHOLE: expression's size differs from type's"); END; END; (* check for alignment problems *) IF (align_in < align_out) OR (align_in MOD align_out # 0) THEN Error.Warn(1,"LOOPHOLE: expression's alignment may differ from type's"); END; (* classify the type of LOOPHOLE operation *) IF array_out THEN IF desig_in THEN p.kind := Kind.D_to_A; ELSIF struct_in THEN p.kind := Kind.S_to_A; ELSE p.kind := Kind.V_to_A; END; ELSIF (src_info.stk_type = dest_info.stk_type) THEN p.kind := Kind.Noop; ELSIF struct_out THEN IF desig_in THEN p.kind := Kind.D_to_S; ELSIF struct_in THEN p.kind := Kind.S_to_S; ELSE p.kind := Kind.V_to_S; END; ELSIF struct_in THEN p.kind := Kind.S_to_V; ELSIF desig_in THEN p.kind := Kind.D_to_V; ELSE p.kind := Kind.V_to_V; END; IF (p.kind = Kind.D_to_A) OR (p.kind = Kind.D_to_S) THEN (* we're going to take the address of this value *) Expr.NeedsAddress (p.expr); END; END Check; PROCEDUREEqCheck (a: P; e: Expr.T; x: M3.EqAssumption): BOOLEAN = BEGIN TYPECASE e OF | NULL => RETURN FALSE; | P(b) => RETURN Type.IsEqual (a.tipe, b.tipe, x) AND Expr.IsEqual (a.expr, b.expr, x); ELSE RETURN FALSE; END; END EqCheck; PROCEDURENeedsAddress (p: P) = BEGIN CASE p.kind OF | Kind.Noop, Kind.D_to_S, Kind.S_to_S, Kind.D_to_V, Kind.S_to_V, Kind.V_to_V => Expr.NeedsAddress (p.expr); | Kind.D_to_A, Kind.S_to_A, Kind.V_to_A, Kind.V_to_S => (* ok, because we build a temporary *) END; END NeedsAddress; PROCEDUREPrep (p: P) = VAR e := p.expr; u := Expr.TypeOf (e); t := p.tipe; t1 : CG.Var; sz, t_align, u_align, z_align: INTEGER; t_cg, u_cg: CG.Type; u_info, t_info: Type.Info; BEGIN IF (p.tmp_cnt > 0) THEN INC (p.tmp_cnt); RETURN; END; u := Type.CheckInfo (u, u_info); t := Type.CheckInfo (t, t_info); t_cg := t_info.stk_type; t_align := t_info.alignment; u_cg := u_info.stk_type; u_align := u_info.alignment; sz := u_info.size; Type.Compile (t); Type.Compile (u); z_align := MAX (t_align, u_align); CASE p.kind OF | Kind.Noop => Expr.Prep (e); | Kind.D_to_A => INC (p.tmp_cnt); Expr.PrepLValue (e, traced := FALSE); Expr.CompileAddress (e, traced := FALSE); p.tmp := BuildArray (p, sz); | Kind.S_to_A => INC (p.tmp_cnt); Expr.Prep (e); Expr.Compile (e); p.tmp := BuildArray (p, sz); | Kind.V_to_A => (* copy the value to a temporary *) INC (p.tmp_cnt); Expr.Prep (e); t1 := CG.Declare_local (M3ID.NoID, sz, z_align, u_cg, Type.GlobalUID (u), in_memory := TRUE, up_level := FALSE, f := CG.Never); Expr.Compile (e); CG.Store (t1, 0, sz, z_align, u_cg); CG.Load_addr_of (t1, 0, z_align); p.tmp := BuildArray (p, sz); | Kind.D_to_S => Expr.PrepLValue (e, traced := FALSE); | Kind.S_to_S => Expr.Prep (e); | Kind.V_to_S => INC (p.tmp_cnt); Expr.Prep (e); p.tmp := CG.Declare_temp (sz, z_align, t_cg, in_memory := TRUE); Expr.Compile (e); CG.Store (p.tmp, 0, sz, z_align, u_cg); | Kind.D_to_V => Expr.Prep (e); | Kind.S_to_V => Expr.Prep (e); | Kind.V_to_V => Expr.Prep (e); END; END Prep; PROCEDURECompile (p: P) = VAR e := p.expr; u := Expr.TypeOf (e); t := p.tipe; sz, t_align, u_align, z_align: INTEGER; t_cg, u_cg: CG.Type; u_info, t_info: Type.Info; BEGIN u := Type.CheckInfo (u, u_info); t := Type.CheckInfo (t, t_info); t_cg := t_info.stk_type; t_align := t_info.alignment; u_cg := u_info.stk_type; u_align := u_info.alignment; sz := u_info.size; Type.Compile (t); Type.Compile (u); z_align := MAX (t_align, u_align); CASE p.kind OF | Kind.Noop => Expr.Compile (e); CG.Boost_alignment (t_align); | Kind.D_to_A, Kind.S_to_A, Kind.V_to_A => PushTmp (p, t_align); | Kind.D_to_S => Expr.CompileAddress (e, traced := FALSE); CG.Boost_alignment (t_align); | Kind.S_to_S => Expr.Compile (e); CG.Boost_alignment (t_align); | Kind.V_to_S => PushTmp (p, z_align); | Kind.D_to_V => Expr.Compile (e); CG.Loophole (u_cg, t_cg); (*** back-ends have problems with this because floating-point variables may be in floating-point registers... Expr.PrepLValue (e); Expr.CompileLValue (e); CG.Boost_alignment (t_align); CG.Load_indirect (t_cg, 0, sz); ******) | Kind.S_to_V => Expr.Compile (e); CG.Boost_alignment (t_align); CG.Load_indirect (t_cg, 0, sz); | Kind.V_to_V => Expr.Compile (e); CG.Loophole (u_cg, t_cg); END; END Compile; PROCEDUREPushTmp (p: P; align: INTEGER) = BEGIN DEC (p.tmp_cnt); IF (p.tmp_cnt <= 0) THEN CG.Load_addr_of_temp (p.tmp, 0, align); p.tmp := NIL; ELSE CG.Load_addr_of (p.tmp, 0, align); END; END PushTmp; PROCEDUREBuildArray (p: P; src_size: INTEGER): CG.Var = VAR array : CG.Var; elt := OpenArrayType.OpenType (p.tipe); elt_info: Type.Info; BEGIN elt := Type.CheckInfo (elt, elt_info); (** CG.Check_byte_aligned (); **) array := OpenArrayType.DeclareTemp (p.tipe); CG.Store_addr (array, M3RT.OA_elt_ptr); CG.Load_intt (src_size DIV elt_info.size); CG.Store_int (Target.Integer.cg_type, array, M3RT.OA_size_0); RETURN array; END BuildArray; PROCEDUREPrepLV (p: P; traced: BOOLEAN) = VAR e := p.expr; u := Expr.TypeOf (e); t := p.tipe; sz, t_align, u_align, z_align: INTEGER; t_cg, u_cg: CG.Type; t1 : CG.Var; u_info, t_info: Type.Info; BEGIN IF (p.tmp_cnt > 0) THEN INC (p.tmp_cnt); RETURN; END; u := Type.CheckInfo (u, u_info); t := Type.CheckInfo (t, t_info); t_align := t_info.alignment; u_align := u_info.alignment; z_align := MAX (t_align, u_align); t_cg := t_info.stk_type; u_cg := u_info.stk_type; sz := u_info.size; Type.Compile (t); Type.Compile (u); CASE p.kind OF | Kind.Noop, Kind.D_to_S, Kind.S_to_S, Kind.D_to_V, Kind.S_to_V, Kind.V_to_V => Expr.PrepLValue (p.expr, traced); | Kind.D_to_A => INC (p.tmp_cnt); Expr.PrepLValue (e, traced); Expr.CompileLValue (e, traced); p.tmp := BuildArray (p, sz); | Kind.S_to_A => INC (p.tmp_cnt); Expr.Prep (e); Expr.Compile (e); p.tmp := BuildArray (p, sz); | Kind.V_to_A => (* copy the value to a temporary *) INC (p.tmp_cnt); Expr.Prep (e); t1 := CG.Declare_local (M3ID.NoID, sz, z_align, u_cg, Type.GlobalUID (u), in_memory := TRUE, up_level := FALSE, f := CG.Never); Expr.Compile (e); CG.Store (t1, 0, sz, z_align, u_cg); CG.Load_addr_of (t1, 0, z_align); p.tmp := BuildArray (p, sz); | Kind.V_to_S => INC (p.tmp_cnt); Expr.Prep (e); p.tmp := CG.Declare_temp (sz, z_align, t_cg, in_memory := TRUE); Expr.Compile (e); CG.Store (p.tmp, 0, sz, z_align, u_cg); END; END PrepLV; PROCEDURECompileLV (p: P; traced: BOOLEAN) = VAR e := p.expr; u := Expr.TypeOf (e); t := p.tipe; sz, t_align, u_align, z_align: INTEGER; t_cg, u_cg: CG.Type; u_info, t_info: Type.Info; BEGIN u := Type.CheckInfo (u, u_info); t := Type.CheckInfo (t, t_info); t_align := t_info.alignment; u_align := u_info.alignment; z_align := MAX (t_align, u_align); t_cg := t_info.stk_type; u_cg := u_info.stk_type; sz := u_info.size; Type.Compile (t); Type.Compile (u); CASE p.kind OF | Kind.Noop, Kind.S_to_S, Kind.D_to_V, Kind.S_to_V, Kind.V_to_V => Expr.CompileLValue (p.expr, traced); CG.Boost_alignment (t_align); | Kind.D_to_S => Expr.CompileLValue (p.expr, traced); CG.Boost_alignment (t_align); (* Inhibit some optimization that causes compilation to fail. e.g.: * m3core/src/float/IEEE/RealFloat.m3: * In function 'RealFloat__CopySign': * internal compiler error: in convert_move, at expr.c:371 * * ?Force() inhibits optimizations done by m3front/src/misc/CG.m3? * ?The particular optimizations are removal of address taken and * pointer indirections? ?Leaving the address taken inhibits * gcc optimization? ?Given that this is LOOPHOLE and floating point, * inhibiting optimization is very ok? *) IF FloatType[t_cg] # FloatType[u_cg] THEN CG.Force (); END; | Kind.D_to_A, Kind.S_to_A, Kind.V_to_A => PushTmp (p, t_align); | Kind.V_to_S => PushTmp (p, z_align); END; END CompileLV; PROCEDUREFold (p: P): Expr.T = VAR e: Expr.T; BEGIN e := Expr.ConstValue (p.expr); IF (e = NIL) THEN RETURN NIL END; p.expr := e; RETURN p; END Fold; PROCEDUREBounder (p: P; VAR min, max: Target.Int) = VAR min1, max1: Target.Int; BEGIN Expr.GetBounds (p.expr, min, max); EVAL Type.GetBounds (p.tipe, min1, max1); IF TInt.LT (min, min1) THEN min := min1 END; IF TInt.LT (max1, max) THEN max := max1 END; END Bounder; PROCEDUREIsDesignator (p: P; <*UNUSED*> lhs: BOOLEAN): BOOLEAN = BEGIN RETURN Expr.IsDesignator (p.expr); END IsDesignator; PROCEDUREIsWritable (p: P; lhs: BOOLEAN): BOOLEAN = BEGIN RETURN Expr.IsWritable (p.expr, lhs); END IsWritable; PROCEDUREGenFPLiteral (p: P; buf: M3Buf.T) = BEGIN Expr.GenFPLiteral (p.expr, buf); END GenFPLiteral; PROCEDURENoteWrites (p: P) = BEGIN Expr.NoteWrite (p.expr); END NoteWrites; BEGIN END CastExpr.