- 
          
- 
                Notifications
    You must be signed in to change notification settings 
- Fork 656
convert divcoeff.c to D rebooted #7714
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
|  | @@ -2,38 +2,47 @@ | |
| * Compiler implementation of the | ||
| * $(LINK2 http://www.dlang.org, D programming language). | ||
| * | ||
| * Copyright: Copyright (C) 2013-2018 by The D Language Foundation, All Rights Reserved | ||
| * Copyright: Copyright (c) 2013-2018 by The D Language Foundation, All Rights Reserved | ||
| * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) | ||
| * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) | ||
| * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/backend/divcoeff.c, backend/divcoeff.c) | ||
| * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/backend/divcoeff.d, backend/divcoeff.d) | ||
| */ | ||
|  | ||
| /*************************************************** | ||
| * Algorithms from "Division by Invariant Integers using Multiplication" | ||
| * by Torbjoern Granlund and Peter L. Montgomery | ||
| */ | ||
|  | ||
| #include <stdio.h> | ||
| #include <assert.h> | ||
| import core.stdc.stdio; | ||
|  | ||
| // This MUST MATCH typedef targ_ullong in cdef.h. | ||
| #if defined(__UINT64_TYPE__) && !defined(__APPLE__) | ||
| typedef __UINT64_TYPE__ ullong; | ||
| #elif defined(__UINTMAX_TYPE__) | ||
| typedef __UINTMAX_TYPE__ ullong; | ||
| #else | ||
| typedef unsigned long long ullong; | ||
| #endif | ||
| extern (C++): | ||
|  | ||
| void test_udiv_coefficients(); | ||
| alias ullong = ulong; | ||
|  | ||
| /* unsigned 128 bit math | ||
| */ | ||
|  | ||
| #define SIGN64(x) ((long long)(x) < 0) | ||
| #define SHL128(dh,dl, xh,xl) ((dh = (xh << 1) | SIGN64(xl)), (dl = xl << 1)) | ||
| #define SHR128(dh,dl, xh,xl) ((dl = (xl >> 1) | ((xh & 1) << 63)),(dh = xh >> 1)) | ||
| #define XltY128(xh,xl,yh,yl) (xh < yh || (xh == yh && xl < yl)) | ||
| bool SIGN64(ullong x) | ||
| { | ||
| return cast(long)x < 0; | ||
| } | ||
|  | ||
| void SHL128(out ullong dh, out ullong dl, ullong xh,ullong xl) | ||
| { | ||
| dh = (xh << 1) | SIGN64(xl); | ||
| dl = xl << 1; | ||
| } | ||
|  | ||
| void SHR128(out ullong dh, out ullong dl, ullong xh,ullong xl) | ||
| { | ||
| dl = (xl >> 1) | ((xh & 1) << 63); | ||
| dh = xh >> 1; | ||
| } | ||
|  | ||
| bool XltY128(ullong xh, ullong xl, ullong yh, ullong yl) | ||
| { | ||
| return xh < yh || (xh == yh && xl < yl); | ||
| } | ||
|  | ||
| void u128Div(ullong xh, ullong xl, ullong yh, ullong yl, ullong *pqh, ullong *pql) | ||
| { | ||
|  | @@ -43,10 +52,10 @@ void u128Div(ullong xh, ullong xl, ullong yh, ullong yl, ullong *pqh, ullong *pq | |
|  | ||
| //ullong xxh = xh, xxl = xl, yyh = yh, yyl = yl; | ||
|  | ||
| assert(yh || yl); // no div-by-0 bugs | ||
| // assert(yh || yl); // no div-by-0 bugs | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not use the  Or maybe @CyberShadow can update DAutoTest to use 2.068.2 as initial bootstrap compiler? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't want to redo the asserts, as that doesn't scale to the rest of the back end. What's needed is to upgrade the boot compiler to 2.074. But that's for after this PR. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 
 Well, I thought it helps porting when the  | ||
|  | ||
| // left justify y | ||
| unsigned shiftcount = 1; | ||
| uint shiftcount = 1; | ||
| if (!yh) | ||
| { yh = yl; | ||
| yl = 0; | ||
|  | @@ -85,31 +94,32 @@ void u128Div(ullong xh, ullong xl, ullong yh, ullong yl, ullong *pqh, ullong *pq | |
|  | ||
| // Remainder is xh,xl | ||
|  | ||
| #if 0 | ||
| printf("%016llx_%016llx / %016llx_%016llx = %016llx_%016llx\n", xxh,xxl,yyh,yyl,qh,ql); | ||
| if (xxh == 0 && yyh == 0) | ||
| printf("should be %llx\n", xxl / yyl); | ||
| #endif | ||
| version (none) | ||
| { | ||
| printf("%016llx_%016llx / %016llx_%016llx = %016llx_%016llx\n", xxh,xxl,yyh,yyl,qh,ql); | ||
| if (xxh == 0 && yyh == 0) | ||
| printf("should be %llx\n", xxl / yyl); | ||
| } | ||
| } | ||
|  | ||
| /************************************ | ||
| * Implement Algorithm 6.2: Selection of multiplier and shift count | ||
| * Input: | ||
| * N 32 or 64 | ||
| * d divisor (must not be 0 or a power of 2) | ||
| * prec bits of precision desired | ||
| * Params: | ||
| * N = 32 or 64 | ||
| * d = divisor (must not be 0 or a power of 2) | ||
| * prec = bits of precision desired | ||
| * Output: | ||
| * *pm factor | ||
| * *pshpost post shift | ||
| * *pm = factor | ||
| * *pshpost = post shift | ||
| * Returns: | ||
| * true m >= 2**N | ||
| */ | ||
|  | ||
| bool choose_multiplier(int N, ullong d, int prec, ullong *pm, int *pshpost) | ||
| extern (C) bool choose_multiplier(int N, ullong d, int prec, ullong *pm, int *pshpost) | ||
| { | ||
| assert(N == 32 || N == 64); | ||
| assert(prec <= N); | ||
| assert(d > 1 && (d & (d - 1))); | ||
| // assert(N == 32 || N == 64); | ||
| // assert(prec <= N); | ||
| // assert(d > 1 && (d & (d - 1))); | ||
|  | ||
| // Compute b such that 2**(b-1) < d <= 2**b | ||
| // which is the number of significant bits in d | ||
|  | @@ -127,10 +137,10 @@ bool choose_multiplier(int N, ullong d, int prec, ullong *pm, int *pshpost) | |
| if (N == 32) | ||
| { | ||
| // mlow = (2**(N + b)) / d | ||
| ullong mlow = (1ULL << (N + b)) / d; | ||
| ullong mlow = (1UL << (N + b)) / d; | ||
|  | ||
| // uhigh = (2**(N + b) + 2**(N + b - prec)) / d | ||
| ullong mhigh = ((1ULL << (N + b)) + (1ULL << (N + b - prec))) / d; | ||
| ullong mhigh = ((1UL << (N + b)) + (1UL << (N + b - prec))) / d; | ||
|  | ||
| while (mlow/2 < mhigh/2 && shpost) | ||
| { | ||
|  | @@ -140,27 +150,27 @@ bool choose_multiplier(int N, ullong d, int prec, ullong *pm, int *pshpost) | |
| } | ||
|  | ||
| *pm = mhigh & 0xFFFFFFFF; | ||
| mhighbit = mhigh >> N; | ||
| mhighbit = (mhigh >> N) != 0; | ||
| } | ||
| else if (N == 64) | ||
| { | ||
| // Same as for N==32, but use 128 bit unsigned arithmetic | ||
|  | ||
| // mlow = (2**(N + b)) / d | ||
| ullong mlowl = 0; | ||
| ullong mlowh = 1ULL << b; | ||
| ullong mlowh = 1UL << b; | ||
|  | ||
| // mlow /= d | ||
| u128Div(mlowh, mlowl, 0, d, &mlowh, &mlowl); | ||
|  | ||
| // mhigh = (2**(N + b) + 2**(N + b - prec)) / d | ||
| ullong mhighl = 0; | ||
| ullong mhighh = 1ULL << b; | ||
| ullong mhighh = 1UL << b; | ||
| int e = N + b - prec; | ||
| if (e < 64) | ||
| mhighl = 1ULL << e; | ||
| mhighl = 1UL << e; | ||
| else | ||
| mhighh |= 1ULL << (e - 64); | ||
| mhighh |= 1UL << (e - 64); | ||
|  | ||
| // mhigh /= d | ||
| u128Div(mhighh, mhighl, 0, d, &mhighh, &mhighl); | ||
|  | @@ -195,8 +205,8 @@ bool choose_multiplier(int N, ullong d, int prec, ullong *pm, int *pshpost) | |
| *pm = mhighl; | ||
| mhighbit = mhighh & 1; | ||
| } | ||
| else | ||
| assert(0); | ||
| // else | ||
| // assert(0); | ||
|  | ||
| *pshpost = shpost; | ||
| return mhighbit; | ||
|  | @@ -221,12 +231,8 @@ bool choose_multiplier(int N, ullong d, int prec, ullong *pm, int *pshpost) | |
| * q = SRL(MULUH(m, SRL(n, shpre)), shpost) | ||
| */ | ||
|  | ||
| bool udiv_coefficients(int N, ullong d, int *pshpre, ullong *pm, int *pshpost) | ||
| extern (C) bool udiv_coefficients(int N, ullong d, int *pshpre, ullong *pm, int *pshpost) | ||
| { | ||
| #ifdef DEBUG | ||
| test_udiv_coefficients(); | ||
| #endif | ||
|  | ||
| bool mhighbit = choose_multiplier(N, d, N, pm, pshpost); | ||
| if (mhighbit && (d & 1) == 0) | ||
| { | ||
|  | @@ -237,21 +243,15 @@ bool udiv_coefficients(int N, ullong d, int *pshpre, ullong *pm, int *pshpost) | |
| } | ||
| *pshpre = e; | ||
| mhighbit = choose_multiplier(N, d, N - e, pm, pshpost); | ||
| assert(mhighbit == false); | ||
| // assert(mhighbit == false); | ||
| } | ||
| else | ||
| *pshpre = 0; | ||
| return mhighbit; | ||
| } | ||
|  | ||
| #ifdef DEBUG | ||
| void test_udiv_coefficients() | ||
| unittest | ||
| { | ||
| static bool tested = false; | ||
| if (tested) | ||
| return; | ||
| tested = true; | ||
|  | ||
| struct S | ||
| { | ||
| int N; | ||
|  | @@ -260,10 +260,10 @@ void test_udiv_coefficients() | |
| int highbit; | ||
| ullong m; | ||
| int shpost; | ||
| }; | ||
| } | ||
|  | ||
| static S table[] = | ||
| { | ||
| static immutable S[14] table = | ||
| [ | ||
| { 32, 10, 0, 0, 0xCCCCCCCD, 3 }, | ||
| { 32, 13, 0, 0, 0x4EC4EC4F, 2 }, | ||
| { 32, 14, 1, 0, 0x92492493, 2 }, | ||
|  | @@ -279,39 +279,40 @@ void test_udiv_coefficients() | |
| { 64, 17, 0, 0, 0xF0F0F0F0F0F0F0F1, 4 }, | ||
| { 64, 100, 2, 0, 0x28F5C28F5C28F5C3, 2 }, | ||
| { 64, 14007, 0, 1, 0x2B71840C5ADF02C3, 14 }, | ||
| }; | ||
| ]; | ||
|  | ||
| for (int i = 0; i < sizeof(table)/sizeof(table[0]); i++) | ||
| { S *ps = &table[i]; | ||
| for (int i = 0; i < table.length; i++) | ||
| { const ps = &table[i]; | ||
|  | ||
| ullong m; | ||
| int shpre; | ||
| int shpost; | ||
| bool mhighbit = udiv_coefficients(ps->N, ps->d, &shpre, &m, &shpost); | ||
| bool mhighbit = udiv_coefficients(ps.N, ps.d, &shpre, &m, &shpost); | ||
|  | ||
| //printf("[%d] %d %d %llx %d\n", i, shpre, mhighbit, m, shpost); | ||
| assert(shpre == ps->shpre); | ||
| assert(mhighbit == (bool)ps->highbit); | ||
| assert(m == ps->m); | ||
| assert(shpost == ps->shpost); | ||
| // assert(shpre == ps.shpre); | ||
| // assert(mhighbit == ps.highbit); | ||
| // assert(m == ps.m); | ||
| // assert(shpost == ps.shpost); | ||
| } | ||
| } | ||
| #endif | ||
|  | ||
| #if 0 | ||
| #include <stdlib.h> | ||
|  | ||
| void main(int argc, char **argv) | ||
| version (none) | ||
| { | ||
| if (argc == 2) | ||
| import core.stdc.stdlib; | ||
|  | ||
| extern (D) int main(string[] args) | ||
| { | ||
| ullong d = atoi(argv[1]); | ||
| ullong m; | ||
| int shpre; | ||
| int shpost; | ||
| bool mhighbit = udiv_coefficients(64, d, &shpre, &m, &shpost); | ||
| if (args.length == 2) | ||
| { | ||
| ullong d = atoi(args[1].ptr); | ||
| ullong m; | ||
| int shpre; | ||
| int shpost; | ||
| bool mhighbit = udiv_coefficients(64, d, &shpre, &m, &shpost); | ||
|  | ||
| printf("%d %d %llx, %d\n", shpre, mhighbit, m, shpost); | ||
| printf("%d %d %llx, %d\n", shpre, mhighbit, m, shpost); | ||
| } | ||
| return 0; | ||
| } | ||
| } | ||
| #endif | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI: auto-tester needs to be bumped too, see the discussion on the previous PR and the NG discussion - especially Martin's reply.