aboutsummaryrefslogtreecommitdiffstats
path: root/libs/bigint/BigIntegerAlgorithms.cc
blob: 7edebda76a8e17de58dcb3476bc02e3d6be5a249 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include "BigIntegerAlgorithms.hh"

BigUnsigned gcd(BigUnsigned a, BigUnsigned b) {
	BigUnsigned trash;
	// Neat in-place alternating technique.
	for (;;) {
		if (b.isZero())
			return a;
		a.divideWithRemainder(b, trash);
		if (a.isZero())
			return b;
		b.divideWithRemainder(a, trash);
	}
}

void extendedEuclidean(BigInteger m, BigInteger n,
		BigInteger &g, BigInteger &r, BigInteger &s) {
	if (&g == &r || &g == &s || &r == &s)
		throw "BigInteger extendedEuclidean: Outputs are aliased";
	BigInteger r1(1), s1(0), r2(0), s2(1), q;
	/* Invariants:
	 * r1*m(orig) + s1*n(orig) == m(current)
	 * r2*m(orig) + s2*n(orig) == n(current) */
	for (;;) {
		if (n.isZero()) {
			r = r1; s = s1; g = m;
			return;
		}
		// Subtract q times the second invariant from the first invariant.
		m.divideWithRemainder(n, q);
		r1 -= q*r2; s1 -= q*s2;

		if (m.isZero()) {
			r = r2; s = s2; g = n;
			return;
		}
		// Subtract q times the first invariant from the second invariant.
		n.divideWithRemainder(m, q);
		r2 -= q*r1; s2 -= q*s1;
	}
}

BigUnsigned modinv(const BigInteger &x, const BigUnsigned &n) {
	BigInteger g, r, s;
	extendedEuclidean(x, n, g, r, s);
	if (g == 1)
		// r*x + s*n == 1, so r*x === 1 (mod n), so r is the answer.
		return (r % n).getMagnitude(); // (r % n) will be nonnegative
	else
		throw "BigInteger modinv: x and n have a common factor";
}

BigUnsigned modexp(const BigInteger &base, const BigUnsigned &exponent,
		const BigUnsigned &modulus) {
	BigUnsigned ans = 1, base2 = (base % modulus).getMagnitude();
	BigUnsigned::Index i = exponent.bitLength();
	// For each bit of the exponent, most to least significant...
	while (i > 0) {
		i--;
		// Square.
		ans *= ans;
		ans %= modulus;
		// And multiply if the bit is a 1.
		if (exponent.getBit(i)) {
			ans *= base2;
			ans %= modulus;
		}
	}
	return ans;
}
span> package Trans.Chap3 is -- Translate the subtype of an object, since an object can define -- a subtype. -- This can be done only for a declaration. -- DECL must have an identifier and a type. procedure Translate_Object_Subtype (Decl : Iir; With_Vars : Boolean := True); procedure Elab_Object_Subtype (Def : Iir); -- Translate the subtype of a literal. -- This can be done not at declaration time, ie no variables are created -- for this subtype. --procedure Translate_Literal_Subtype (Def : Iir); -- Translation of a type definition or subtype indication. -- 1. Create corresponding Ortho type. -- 2. Create bounds type -- 3. Create bounds declaration -- 4. Create bounds constructor -- 5. Create type descriptor declaration -- 6. Create type descriptor constructor procedure Translate_Type_Definition (Def : Iir); -- Translate subprograms for types. procedure Translate_Type_Subprograms (Decl : Iir; Kind : Subprg_Translate_Kind); function Create_Static_Composite_Subtype_Layout (Def : Iir) return O_Cnode; -- Same as Translate_type_definition only for std.standard.boolean and -- std.standard.bit. procedure Translate_Bool_Type_Definition (Def : Iir); -- Call lock or unlock on a protected object. procedure Call_Ghdl_Protected_Procedure (Type_Def : Iir; Proc : O_Dnode); procedure Translate_Protected_Type_Body (Bod : Iir); procedure Translate_Protected_Type_Body_Subprograms_Spec (Bod : Iir); procedure Translate_Protected_Type_Body_Subprograms_Body (Bod : Iir); -- DEF derives (using the Ada meaning) of PARENT_TYPE, ie DEF has new -- constraints on PARENT_TYPE. procedure Translate_Subtype_Definition (Def : Iir; Parent_Type : Iir; With_Vars : Boolean := True); -- Translate a proper subtype indication. procedure Translate_Subtype_Indication (Def : Iir; With_Vars : Boolean); procedure Translate_Named_Subtype_Definition (Def : Iir; Id : Name_Id); -- When there is no name for the subtype (eg: the subtype of a string or -- of an aggregate). There is also no type mark. procedure Translate_Anonymous_Subtype_Definition (Def : Iir; With_Vars : Boolean); -- It generates code to do type elaboration. procedure Elab_Type_Declaration (Decl : Iir); procedure Elab_Subtype_Declaration (Decl : Iir_Subtype_Declaration); -- Builders. -- A complex type is a type whose size is not locally static. -- -- The most simple example is an unidimensionnl array whose range -- depends on generics. -- -- We call first order complex type any array whose bounds are not -- locally static and whose sub-element size is locally static. -- -- First order complex type objects are represented by a pointer to an -- array of sub-element, and the storage area for the array is -- allocated at run-time. -- -- Since a sub-element type may be a complex type, a type may be -- complex because one of its sub-element type is complex. -- EG, a record type whose one element is a complex array. -- -- A type may be complex either because it is a first order complex -- type (ie an array whose bounds are not locally static) or because -- one of its sub-element type is such a type (this is recursive). -- -- We call second order complex type a complex type that is not of first -- order. -- We call third order complex type a second order complex type which is -- an array whose bounds are not locally static. -- -- In a complex type, sub-element of first order complex type are -- represented by a pointer. -- Any complex type object (constant, signal, variable, port, generic) -- is represented by a pointer. -- -- Creation of a second or third order complex type object consists in -- allocating the memory and building the object. -- Building a object consists in setting internal pointers. -- -- A complex type has always a non-null INFO.C, and its size is computed -- during elaboration. -- -- For a second or third order complex type, INFO.C.BUILDER_NEED_FUNC -- is set to TRUE. -- Functions for fat array. -- Fat array are array whose size is not known at compilation time. -- This corresponds to an unconstrained array or a non locally static -- constrained array. -- A fat array is a structure containing 2 fields: -- * base: a pointer to the data of the array. -- * bounds: a pointer to a structure containing as many fields as -- number of dimensions; these fields are a structure describing the -- range of the dimension. procedure Gen_Call_Type_Builder (Layout : Mnode; Var_Type : Iir; Kind : Object_Kind_Type); -- If the element subtype of ARR_TYPE is unbounded, create a fat pointer, -- set the bounds of it (from ARR), and return it. -- Otherwise, return a null mnode. -- Used to build a var for a subelement of ARR. function Create_Maybe_Fat_Array_Element (Arr : Mnode; Arr_Type : Iir) return Mnode; -- If the element subtype of the array is unbounded, set the base of VAR -- from EL, and return it. -- Otherwise directly return EL (VAR must be null). function Assign_Maybe_Fat_Array_Element (Var : Mnode; El : Mnode) return Mnode; -- Index array BASE of type ATYPE with INDEX. -- INDEX must be of type ghdl_index_type, thus no bounds checks are -- performed. function Index_Base (Base : Mnode; Atype : Iir; Index : O_Enode) return Mnode; -- Index array ARR of type ATYPE with INDEX. function Index_Array (Arr : Mnode; Atype : Iir; Index : O_Enode) return Mnode; -- Same for for slicing. function Slice_Base (Base : Mnode; Atype : Iir; Index : O_Enode) return Mnode; -- Get the length of the array (the number of elements). function Get_Array_Length (Arr : Mnode; Atype : Iir) return O_Enode; -- Get the number of elements for bounds BOUNDS. BOUNDS are -- automatically stabilized if necessary. function Get_Bounds_Length (Bounds : Mnode; Atype : Iir) return O_Enode; -- Get the number of elements in array ATYPE. function Get_Array_Type_Length (Atype : Iir) return O_Enode; -- Get the base of array or record OBJ. If OBJ is already constrained, -- return it. function Get_Composite_Base (Obj : Mnode) return Mnode; -- Get the base of array or record OBJ; but if OBJ is already constrained, -- convert it to the base of an unbounded object (so this unboxes the -- records). function Get_Composite_Unbounded_Base (Obj : Mnode) return Mnode; -- Get the bounds of composite ARR (an array or an unbounded record). function Get_Composite_Bounds (Obj : Mnode) return Mnode; -- Get the range ot ATYPE. function Type_To_Range (Atype : Iir) return Mnode; -- Get length of range R. function Range_To_Length (R : Mnode) return Mnode; -- Get direction of range R. function Range_To_Dir (R : Mnode) return Mnode; -- Get left/right bounds for range R. function Range_To_Left (R : Mnode) return Mnode; function Range_To_Right (R : Mnode) return Mnode; -- Get range for dimension DIM (1 based) of array bounds B of type -- ATYPE. function Bounds_To_Range (B : Mnode; Atype : Iir; Dim : Positive) return Mnode; -- Get the range of dimension DIM (1 based) of array ARR of type ATYPE. function Get_Array_Range (Arr : Mnode; Atype : Iir; Dim : Positive) return Mnode; -- Get array/record bounds for type ATYPE. function Get_Composite_Type_Bounds (Atype : Iir) return Mnode; -- Return a pointer to the base from bounds_acc ACC. function Get_Bounds_Acc_Base (Acc : O_Enode; D_Type : Iir) return O_Enode; -- Return bounds from layout B. function Layout_To_Bounds (B : Mnode) return Mnode; -- From a record layout B, return the layout of element EL. EL must be -- an unbounded element. function Record_Layout_To_Element_Layout (B : Mnode; El : Iir) return Mnode; -- From an unbounded record bounds B, get the bounds for (unbounded) -- element EL. function Record_Bounds_To_Element_Bounds (B : Mnode; El : Iir) return Mnode; -- Return the offset for field EL in record B. function Record_Layout_To_Element_Offset (B : Mnode; El : Iir; Kind : Object_Kind_Type) return O_Lnode; -- From an unbounded array bounds B, get the bounds for the (unbounded) -- element. function Array_Bounds_To_Element_Bounds (B : Mnode; Atype : Iir) return Mnode; -- From unbounded array bounds B, get the layout of the unbounded element. function Array_Bounds_To_Element_Layout (B : Mnode; Atype : Iir) return Mnode; -- Deallocate OBJ. procedure Gen_Deallocate (Obj : O_Enode); -- Performs deallocation of PARAM (the parameter of a deallocate call). procedure Translate_Object_Deallocation (Param : Iir); -- Copy bounds from SRC to DEST. procedure Copy_Bounds (Dest : O_Enode; Src : O_Enode; Obj_Type : Iir); procedure Copy_Bounds (Dest : Mnode; Src : Mnode; Obj_Type : Iir); -- Allocate an object of type OBJ_TYPE and set RES. -- RES must be a stable access of type ortho_ptr_type. -- For an unconstrained array, BOUNDS is a pointer to the boundaries of -- the object, which are copied. procedure Translate_Object_Allocation (Res : in out Mnode; Alloc_Kind : Allocation_Kind; Obj_Type : Iir; Bounds : Mnode); -- Low level copy of SRC to DEST. Both have the same type, OBJ_TYPE. -- There is no length check, so arrays must be of the same length. procedure Translate_Object_Copy (Dest : Mnode; Src : Mnode; Obj_Type : Iir); -- Get size (in bytes with type ghdl_index_type) of subtype ATYPE. -- For an unconstrained array, BOUNDS must be set, otherwise it may be a -- null_mnode. function Get_Subtype_Size (Atype : Iir; Bounds : Mnode; Kind : Object_Kind_Type) return O_Enode; -- Get size (in bytes with type ghdl_index_type) of object OBJ. -- For an unconstrained array, OBJ must be really an object, otherwise, -- it may be the result of T2M. function Get_Object_Size (Obj : Mnode; Obj_Type : Iir) return O_Enode; -- Allocate the base of an unbounded composite, whose length is -- determined from the bounds (already set). -- RES_PTR is a pointer to the fat pointer (must be a stable variable: it -- can be referenced several times). -- ARR_TYPE is the type of the composite. procedure Allocate_Unbounded_Composite_Base (Alloc_Kind : Allocation_Kind; Res : Mnode; Arr_Type : Iir); -- Allocate the bounds for type OBJ_TYPE and assign it to unbounded object -- RES. Then copy bounds from BOUNDS to the object. procedure Allocate_Unbounded_Composite_Bounds (Alloc_Kind : Allocation_Kind; Res : Mnode; Obj_Type : Iir); -- Used for alias: create the vars for the subtype of the name (when the -- name is a slice). The identifier prefix must have been set. procedure Translate_Array_Subtype (Arr_Type : Iir); procedure Elab_Array_Subtype (Arr_Type : Iir); -- Create the bounds for SUB_TYPE. -- SUB_TYPE is expected to be a non-static, anonymous array or record -- subtype. procedure Create_Composite_Subtype (Sub_Type : Iir); -- Return TRUE if VALUE is not is the range specified by ATYPE. -- VALUE must be stable. function Not_In_Range (Value : O_Dnode; Atype : Iir) return O_Enode; -- Return TRUE if base type of ATYPE is larger than its bounds, ie -- if a value of type ATYPE may be out of range. function Need_Range_Check (Expr : Iir; Atype : Iir) return Boolean; -- Generate an error if VALUE (computed from EXPR which may be NULL_IIR -- if not from a tree) is not in range specified by ATYPE. procedure Check_Range (Value : O_Dnode; Expr : Iir; Atype : Iir; Loc : Iir); -- Insert a scalar check for VALUE of type ATYPE. EXPR may be NULL_IIR. function Insert_Scalar_Check (Value : O_Enode; Expr : Iir; Atype : Iir; Loc : Iir) return O_Enode; -- The base type of EXPR and the base type of ATYPE must be the same. -- If the type is a scalar type, and if a range check is needed, this -- function inserts the check. Otherwise, it returns VALUE. function Maybe_Insert_Scalar_Check (Value : O_Enode; Expr : Iir; Atype : Iir) return O_Enode; -- Return True iff all indexes of L_TYPE and R_TYPE have the same -- length. They must be constrained. function Locally_Array_Match (L_Type, R_Type : Iir) return Tri_State_Type; -- Check bounds of L match bounds of R. -- If L_TYPE (resp. R_TYPE) is not a thin composite type, then L_NODE -- (resp. R_NODE) are not used (and may be Mnode_Null). -- If L_TYPE (resp. T_TYPE) is a fat type, then L_NODE (resp. R_NODE) -- must designate the object. procedure Check_Composite_Match (L_Type : Iir; L_Node : Mnode; R_Type : Iir; R_Node : Mnode; Loc : Iir); -- Create a subtype range to be stored into RES from length LENGTH, which -- is of type INDEX_TYPE. -- This is done according to rules 7.2.4 of LRM93, ie: -- direction and left bound of the range is the same of INDEX_TYPE. -- LENGTH is a variable. LOC is the location in case of error. procedure Create_Range_From_Length (Index_Type : Iir; Length : O_Dnode; Res : Mnode; Loc : Iir); end Trans.Chap3;