Tcl Source Code

Check-in [852981a34b]
Login
Bounty program for improvements to Tcl and certain Tcl packages.
Tcl 2019 Conference, Houston/TX, US, Nov 4-8
Send your abstracts to tclconference@googlegroups.com
or submit via the online form by Sep 9.

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:
[kennykb-numerics-branch]
* generic/tclExecute.c: Improved performance of comparison opcodes and bitwise operations and removed yet more dead code.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | kennykb-numerics-branch
Files: files | file ages | folders
SHA1:852981a34b86a60533cafa5aa1aa11f0f2ec2396
User & Date: dgp 2005-10-07 18:01:40
Context
2005-10-07
20:15
[kennykb-numerics-branch]
* generic/tclInt.h: Made #undef NO_WIDE_TYPE the defa...
check-in: c420c12ecc user: dgp tags: kennykb-numerics-branch
18:01
[kennykb-numerics-branch]
* generic/tclExecute.c: Improved performance of compariso...
check-in: 852981a34b user: dgp tags: kennykb-numerics-branch
15:51
[kennykb-numerics-branch]
* generic/tclExecute.c: Improved performance of compariso...
check-in: 7818e1ffac user: dgp tags: kennykb-numerics-branch
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to ChangeLog.

1
2
3
4
5
6
7
8
9
10
11
12
13
2005-10-07  Don Porter  <dgp@users.sourceforge.net>

	[kennykb-numerics-branch]

	* generic/tclExecute.c:	Improved performance of comparison opcodes
	and removed yet more dead code.

2005-10-06  Don Porter  <dgp@users.sourceforge.net>

	[kennykb-numerics-branch]

	* generic/tclExecute.c:	Improved performance of INST_RSHIFT and
	INST_LSHIFT.





|







1
2
3
4
5
6
7
8
9
10
11
12
13
2005-10-07  Don Porter  <dgp@users.sourceforge.net>

	[kennykb-numerics-branch]

	* generic/tclExecute.c:	Improved performance of comparison opcodes
	and bitwise operations and removed yet more dead code.

2005-10-06  Don Porter  <dgp@users.sourceforge.net>

	[kennykb-numerics-branch]

	* generic/tclExecute.c:	Improved performance of INST_RSHIFT and
	INST_LSHIFT.

Changes to generic/tclExecute.c.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
....
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
....
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
3681
3682
3683
3684
3685
3686
3687
3688
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756
3757
3758
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
3784
3785
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833
3834
3835
3836
3837
3838
3839
3840
3841
3842
3843
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
3917
3918
3919
3920
3921
3922
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
3982
3983
3984
3985
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
....
4158
4159
4160
4161
4162
4163
4164
4165
4166
4167
4168
4169
4170
4171
4172
4173
4174
4175
4176
4177
4178
4179
4180
4181
4182

4183
4184
4185
4186
4187
4188

















4189
4190
4191
4192
4193
4194
4195
4196
4197
4198
4199
4200
4201
4202
4203
4204
4205
4206
4207

4208
4209
4210
4211
4212
4213
4214
4215
4216
4217
4218
4219
4220
4221
4222
4223
4224
4225
4226
4227
4228
4229
4230
4231
4232
4233
4234
4235
4236
4237

4238
4239
4240
4241
4242
4243
4244
4245
4246
4247
4248
4249
4250
4251
4252
4253
4254
4255
4256
4257
4258
4259
4260
4261
4262
4263
4264
4265
4266
4267
4268

4269
4270
4271
4272
4273
4274
4275
4276
4277
4278
4279
4280
4281
4282
4283
4284
4285
4286
4287
4288
4289
4290
4291
4292
4293
4294
4295
4296
4297
4298

4299
4300
4301
4302
4303
4304
4305
4306
4307
4308
4309
4310
4311
4312







4313


4314


4315



















4316























4317
4318
4319
4320
4321
4322
4323
....
4354
4355
4356
4357
4358
4359
4360
4361
4362
4363
4364
4365
4366
4367
4368
4369
....
4485
4486
4487
4488
4489
4490
4491
4492
4493
4494
4495
4496
4497
4498
4499
4500
4501
4502
4503
4504
4505
4506
4507
4508
4509
4510
4511
4512
4513
4514
4515
4516
4517
4518
4519
4520
4521
4522
4523
4524
4525
4526
4527
4528
4529
4530
4531
4532
4533
4534
4535
4536
4537
4538
4539
4540
4541
4542
4543
4544
4545
4546
4547
4548
4549
4550
4551
 * Copyright (c) 2001 by Kevin B. Kenny.  All rights reserved.
 * Copyright (c) 2002-2005 by Miguel Sofer.
 * Copyright (c) 2005 by Donal K. Fellows.
 *
 * See the file "license.terms" for information on usage and redistribution of
 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclExecute.c,v 1.167.2.52 2005/10/07 15:51:27 dgp Exp $
 */

#include "tclInt.h"
#include "tclCompile.h"
#include "tommath.h"

#include <math.h>
................................................................................
    case INST_JUMP_TRUE1:
	jmpOffset[0] = 2;
	jmpOffset[1] = TclGetInt1AtPtr(pc+1);

    doCondJump:
	valuePtr = *tosPtr;

#if 0
	if (valuePtr->typePtr == &tclIntType) {
	    b = (valuePtr->internalRep.longValue != 0);
	} else if (valuePtr->typePtr == &tclDoubleType) {
	    b = (valuePtr->internalRep.doubleValue != 0.0);
	} else if (valuePtr->typePtr == &tclWideIntType) {
	    Tcl_WideInt w;

	    TclGetWide(w,valuePtr);
	    b = (w != W0);
	} else {
	    /*
	     * Taking b's address impedes it being a register variable (in gcc
	     * at least), so we avoid doing it.
	     */
	    int b1;
	    result = Tcl_GetBooleanFromObj(interp, valuePtr, &b1);
	    if (result != TCL_OK) {
		if ((*pc == INST_JUMP_FALSE1) || (*pc == INST_JUMP_FALSE4)) {
		    jmpOffset[1] = jmpOffset[0];
		}
		TRACE_WITH_OBJ(("%d => ERROR: ", jmpOffset[1]),
			Tcl_GetObjResult(interp));
		goto checkForCatch;
	    }
	    b = b1;
	}
#else
	/* TODO - check claim that taking address of b harms performance */
	/* TODO - consider optimization search for eePtr->constants */
	result = Tcl_GetBooleanFromObj(interp, valuePtr, &b);
	if (result != TCL_OK) {
	    TRACE_WITH_OBJ(("%d => ERROR: ", jmpOffset[
		    ((*pc == INST_JUMP_FALSE1) || (*pc == INST_JUMP_FALSE4))
		    ? 0 : 1]), Tcl_GetObjResult(interp));
	    goto checkForCatch;
	}
#endif

#ifdef TCL_COMPILE_DEBUG
	if (b) {
	    if ((*pc == INST_JUMP_TRUE1) || (*pc == INST_JUMP_TRUE4)) {
		TRACE(("%d => %.20s true, new pc %u\n", jmpOffset[1], O2S(valuePtr),
			(unsigned int)(pc+jmpOffset[1] - codePtr->codeStart)));
	    } else {
................................................................................
	    NEXT_INST_F((iResult? TclGetInt4AtPtr(pc+1) : 5), 2, 0);
	}
#endif
	objResultPtr = eePtr->constants[iResult];
	NEXT_INST_F(0, 2, 1);
    }

#if 0
/*
    case INST_EQ:
    case INST_NEQ:
    case INST_LT:
    case INST_GT:
    case INST_LE:
    case INST_GE:*/ {
	/*
	 * Any type is allowed but the two operands must have the same type.
	 * We will compute value op value2.
	 */

	double d1 = 0.0;	/* Init. avoids compiler warning. */
	double d2 = 0.0;	/* Init. avoids compiler warning. */
	long iResult = 0;	/* Init. avoids compiler warning. */
	Tcl_Obj *valuePtr, *value2Ptr;

#if 0
	long i;
	Tcl_WideInt w;
	int length;
	char *s1 = NULL;	/* Init. avoids compiler warning. */
	char *s2 = NULL;	/* Init. avoids compiler warning. */
	long i2 = 0;		/* Init. avoids compiler warning. */
	Tcl_ObjType *t1Ptr, *t2Ptr;


	value2Ptr = *tosPtr;
	valuePtr  = *(tosPtr - 1);

	/*
	 * Be careful in the equal-object case; 'NaN' isn't supposed to be
	 * equal to even itself. [Bug 761471]
	 */

	t1Ptr = valuePtr->typePtr;
	if (valuePtr == value2Ptr) {
	    /*
	     * If we are numeric already, or a dictionary (which is never like
	     * a single-element list), we can proceed to the main equality
	     * check right now.  Otherwise, we need to try to coerce to a
	     * numeric type so we can see if we've got a NaN but haven't
	     * parsed it as numeric.
	     */
	    if (!IS_NUMERIC_TYPE(t1Ptr) && (t1Ptr != &tclDictType)) {
		if (t1Ptr == &tclListType) {
		    int length;
		    /*
		     * Only a list of length 1 can be NaN or such things.
		     */
		    (void) Tcl_ListObjLength(NULL, valuePtr, &length);
		    if (length == 1) {
			goto mustConvertForNaNCheck;
		    }
		} else {
		    /*
		     * Too bad, we'll have to compute the string and try the
		     * conversion
		     */

		  mustConvertForNaNCheck:
		    s1 = Tcl_GetStringFromObj(valuePtr, &length);
		    if (TclLooksLikeInt(s1, length)) {
			GET_WIDE_OR_INT(iResult, valuePtr, i, w);
		    } else {
			(void) Tcl_GetDoubleFromObj((Tcl_Interp *) NULL,
				valuePtr, &d1);
		    }
		    t1Ptr = valuePtr->typePtr;
		}
	    }

	    switch (*pc) {
	    case INST_EQ:
	    case INST_LE:
	    case INST_GE:
		iResult = !((t1Ptr == &tclDoubleType)
			&& IS_NAN(valuePtr->internalRep.doubleValue));
		break;
	    case INST_LT:
	    case INST_GT:
		iResult = 0;
		break;
	    case INST_NEQ:
		iResult = ((t1Ptr == &tclDoubleType)
			&& IS_NAN(valuePtr->internalRep.doubleValue));
		break;
	    }
	    goto foundResult;
	}

	t2Ptr = value2Ptr->typePtr;

	/*
	 * We only want to coerce numeric validation if neither type is NULL.
	 * A NULL type means the arg is essentially an empty object ("", {} or
	 * [list]).
	 */
	if (!(	   (!t1Ptr && !valuePtr->bytes)
		|| (valuePtr->bytes && !valuePtr->length)
		|| (!t2Ptr && !value2Ptr->bytes)
		|| (value2Ptr->bytes && !value2Ptr->length))) {
	    if (!IS_NUMERIC_TYPE(t1Ptr)) {
		s1 = Tcl_GetStringFromObj(valuePtr, &length);
		if (TclLooksLikeInt(s1, length)) {
		    GET_WIDE_OR_INT(iResult, valuePtr, i, w);
		} else {
		    (void) Tcl_GetDoubleFromObj((Tcl_Interp *) NULL,
			    valuePtr, &d1);
		}
		t1Ptr = valuePtr->typePtr;
	    }
	    if (!IS_NUMERIC_TYPE(t2Ptr)) {
		s2 = Tcl_GetStringFromObj(value2Ptr, &length);
		if (TclLooksLikeInt(s2, length)) {
		    GET_WIDE_OR_INT(iResult, value2Ptr, i2, w);
		} else {
		    (void) Tcl_GetDoubleFromObj((Tcl_Interp *) NULL,
			    value2Ptr, &d2);
		}
		t2Ptr = value2Ptr->typePtr;
	    }
	}
	if (!IS_NUMERIC_TYPE(t1Ptr) || !IS_NUMERIC_TYPE(t2Ptr)) {
	    /*
	     * One operand is not numeric. Compare as strings.  NOTE: strcmp
	     * is not correct for \x00 < \x01, but that is unlikely to occur
	     * here.  We could use the TclUtfNCmp2 to handle this.
	     */
	    int s1len, s2len;
	    s1 = Tcl_GetStringFromObj(valuePtr, &s1len);
	    s2 = Tcl_GetStringFromObj(value2Ptr, &s2len);
	    switch (*pc) {
	    case INST_EQ:
		if (s1len == s2len) {
		    iResult = (strcmp(s1, s2) == 0);
		} else {
		    iResult = 0;
		}
		break;
	    case INST_NEQ:
		if (s1len == s2len) {
		    iResult = (strcmp(s1, s2) != 0);
		} else {
		    iResult = 1;
		}
		break;
	    case INST_LT:
		iResult = (strcmp(s1, s2) < 0);
		break;
	    case INST_GT:
		iResult = (strcmp(s1, s2) > 0);
		break;
	    case INST_LE:
		iResult = (strcmp(s1, s2) <= 0);
		break;
	    case INST_GE:
		iResult = (strcmp(s1, s2) >= 0);
		break;
	    }
	} else if ((t1Ptr == &tclDoubleType) || (t2Ptr == &tclDoubleType)) {
	    /*
	     * Compare as doubles.
	     */
	    if (t1Ptr == &tclDoubleType) {
		d1 = valuePtr->internalRep.doubleValue;
		GET_DOUBLE_VALUE(d2, value2Ptr, t2Ptr);
	    } else {	/* t1Ptr is integer, t2Ptr is double */
		GET_DOUBLE_VALUE(d1, valuePtr, t1Ptr);
		d2 = value2Ptr->internalRep.doubleValue;
	    }
	    switch (*pc) {
	    case INST_EQ:
		iResult = d1 == d2;
		break;
	    case INST_NEQ:
		iResult = d1 != d2;
		break;
	    case INST_LT:
		iResult = d1 < d2;
		break;
	    case INST_GT:
		iResult = d1 > d2;
		break;
	    case INST_LE:
		iResult = d1 <= d2;
		break;
	    case INST_GE:
		iResult = d1 >= d2;
		break;
	    }
	} else if ((t1Ptr == &tclWideIntType) || (t2Ptr == &tclWideIntType)) {
	    Tcl_WideInt w2;
	    /*
	     * Compare as wide ints (neither are doubles)
	     */
	    if (t1Ptr == &tclIntType) {
		w  = Tcl_LongAsWide(valuePtr->internalRep.longValue);
		TclGetWide(w2,value2Ptr);
	    } else if (t2Ptr == &tclIntType) {
		TclGetWide(w,valuePtr);
		w2 = Tcl_LongAsWide(value2Ptr->internalRep.longValue);
	    } else {
		TclGetWide(w,valuePtr);
		TclGetWide(w2,value2Ptr);
	    }
	    switch (*pc) {
	    case INST_EQ:
		iResult = w == w2;
		break;
	    case INST_NEQ:
		iResult = w != w2;
		break;
	    case INST_LT:
		iResult = w < w2;
		break;
	    case INST_GT:
		iResult = w > w2;
		break;
	    case INST_LE:
		iResult = w <= w2;
		break;
	    case INST_GE:
		iResult = w >= w2;
		break;
	    }
	} else {
	    /*
	     * Compare as ints.
	     */
	    i  = valuePtr->internalRep.longValue;
	    i2 = value2Ptr->internalRep.longValue;
	    switch (*pc) {
	    case INST_EQ:
		iResult = i == i2;
		break;
	    case INST_NEQ:
		iResult = i != i2;
		break;
	    case INST_LT:
		iResult = i < i2;
		break;
	    case INST_GT:
		iResult = i > i2;
		break;
	    case INST_LE:
		iResult = i <= i2;
		break;
	    case INST_GE:
		iResult = i >= i2;
		break;
	    }
	}

	TRACE(("%.20s %.20s => %ld\n", O2S(valuePtr), O2S(value2Ptr), iResult));
#else
	int arg1Numeric, arg2Numeric;
	mp_int big1, big2;
	int compare;
	double dummy;

	valuePtr = *(tosPtr - 1);
	arg1Numeric = (TCL_OK == Tcl_GetDoubleFromObj(NULL, valuePtr, &d1));
	if (!arg1Numeric && (valuePtr->typePtr == &tclDoubleType)) {
	    /* NaN first arg: NaN != to everything, other compares are false */
	    iResult = (*pc == INST_NEQ);
	    goto foundResult;
	}
	value2Ptr = *tosPtr;
	if (valuePtr == value2Ptr) {
	    switch (*pc) {
	    case INST_EQ:
	    case INST_LE:
	    case INST_GE:
		iResult = 1;
		goto foundResult;
	    case INST_NEQ:
	    case INST_LT:
	    case INST_GT:
		iResult = 0;
		goto foundResult;
	    }
	}
	arg2Numeric = (TCL_OK == Tcl_GetDoubleFromObj(NULL, value2Ptr, &d2));
	if (!arg2Numeric && (value2Ptr->typePtr == &tclDoubleType)) {
	    /* NaN 2nd arg: NaN != to everything, other compares are false */
	    iResult = (*pc == INST_NEQ);
	    goto foundResult;
	}
	if (!arg1Numeric || !arg2Numeric) {
	    /* At least one non-numeric argument - compare as strings */
	    goto stringCompare;
	}
#if 0
	if (valuePtr->typePtr == &tclDoubleType
	    || value2Ptr->typePtr == &tclDoubleType) {
	    /* At least one double - compare as doubles */
	    switch (*pc) {
	    case INST_EQ:
		iResult = d1 == d2;
		break;
	    case INST_NEQ:
		iResult = d1 != d2;
		break;
	    case INST_LT:
		iResult = d1 < d2;
		break;
	    case INST_GT:
		iResult = d1 > d2;
		break;
	    case INST_LE:
		iResult = d1 <= d2;
		break;
	    case INST_GE:
		iResult = d1 >= d2;
		break;
	    }
	} else {
#endif
	if (valuePtr->typePtr == &tclDoubleType) {
	    if (value2Ptr->typePtr == &tclDoubleType) {
		/* Both args are double - compare as doubles */
	    doubleCompare:
		switch (*pc) {
		case INST_EQ:
		    iResult = d1 == d2;
		    break;
		case INST_NEQ:
		    iResult = d1 != d2;
		    break;
		case INST_LT:
		    iResult = d1 < d2;
		    break;
		case INST_GT:
		    iResult = d1 > d2;
		    break;
		case INST_LE:
		    iResult = d1 <= d2;
		    break;
		case INST_GE:
		    iResult = d1 >= d2;
		    break;
		}
		goto foundResult;
	    }
	    if (TclIsInfinite(d1)) {
		dummy = d1;
	    infinityCompare:
		switch (*pc) {
		case INST_EQ:
		    iResult = 0;
		    break;
		case INST_NEQ:
		    iResult = 1;
		    break;
		case INST_LT:
		case INST_LE:
		    iResult = (dummy < 0.0);
		    break;
		case INST_GT:
		case INST_GE:
		    iResult = (dummy > 0.0);
		    break;
		}
		goto foundResult;
	    }
	    if (modf(d1, &dummy) != 0.0) {
		goto doubleCompare;
	    }
	    TclInitBignumFromDouble(NULL, d1, &big1);
	    Tcl_GetBignumFromObj(NULL, value2Ptr, &big2);
	} else {
	    if (value2Ptr->typePtr == &tclDoubleType) {
		if (TclIsInfinite(d2)) {
		    dummy = -d2;
		    goto infinityCompare;
		}
		if (modf(d2, &dummy) != 0.0) {
		    goto doubleCompare;
		}
		TclInitBignumFromDouble(NULL, d2, &big2);
	    } else {
		Tcl_GetBignumFromObj(NULL, value2Ptr, &big2);
	    }
	    Tcl_GetBignumFromObj(NULL, valuePtr, &big1);
	}
	    /* Compare as bignums */
	    /* TODO: more efficient comparisons of narrow native integers */
	    compare = mp_cmp(&big1, &big2);
	    mp_clear(&big1);
	    mp_clear(&big2);
	    switch (*pc) {
	    case INST_EQ:
		iResult = (compare == MP_EQ);
		break;
	    case INST_NEQ:
		iResult = (compare != MP_EQ);
		break;
	    case INST_LT:
		iResult = (compare == MP_LT);
		break;
	    case INST_GT:
		iResult = (compare == MP_GT);
		break;
	    case INST_LE:
		iResult = (compare != MP_GT);
		break;
	    case INST_GE:
		iResult = (compare != MP_LT);
		break;
	    }
#if 0
	}
#endif
#endif

	/*
	 * Peep-hole optimisation: if you're about to jump, do jump from here.
	 */

    foundResult:
	pc++;
#ifndef TCL_COMPILE_DEBUG
	switch (*pc) {
	case INST_JUMP_FALSE1:
	    NEXT_INST_F((iResult? 2 : TclGetInt1AtPtr(pc+1)), 2, 0);
	case INST_JUMP_TRUE1:
	    NEXT_INST_F((iResult? TclGetInt1AtPtr(pc+1) : 2), 2, 0);
	case INST_JUMP_FALSE4:
	    NEXT_INST_F((iResult? 5 : TclGetInt4AtPtr(pc+1)), 2, 0);
	case INST_JUMP_TRUE4:
	    NEXT_INST_F((iResult? TclGetInt4AtPtr(pc+1) : 5), 2, 0);
	}
#endif
	objResultPtr = eePtr->constants[iResult];
	NEXT_INST_F(0, 2, 1);
    }
#endif

    case INST_LSHIFT:
    case INST_RSHIFT: {
	Tcl_Obj *value2Ptr = *tosPtr;
	Tcl_Obj *valuePtr  = *(tosPtr - 1);
	ClientData ptr1, ptr2;
	int invalid, shift, type1, type2;
	long l;
................................................................................
	TRACE(("%s\n", O2S(objResultPtr)));
	NEXT_INST_F(1, 2, 1);
    }
	
    case INST_BITOR:
    case INST_BITXOR:
    case INST_BITAND: {
	Tcl_Obj *valuePtr, *value2Ptr;
	mp_int big1, big2, bigResult;
	mp_int *Pos, *Neg, *Other;
	int numPos = 0;

	value2Ptr = *tosPtr;
	valuePtr  = *(tosPtr - 1);
	result = Tcl_GetBignumFromObj(NULL, valuePtr, &big1);
	if (result != TCL_OK) {
	    TRACE(("%.20s %.20s => ILLEGAL 1st TYPE %s\n", O2S(valuePtr),
		    O2S(value2Ptr), (valuePtr->typePtr?
		    valuePtr->typePtr->name : "null")));
	    IllegalExprOperandType(interp, pc, valuePtr);
	    goto checkForCatch;
	}
	result = Tcl_GetBignumFromObj(NULL, value2Ptr, &big2);
	if (result != TCL_OK) {
	    mp_clear(&big1);

	    TRACE(("%.20s %.20s => ILLEGAL 2nd TYPE %s\n", O2S(valuePtr),
		    O2S(value2Ptr), (value2Ptr->typePtr?
		    value2Ptr->typePtr->name : "null")));
	    IllegalExprOperandType(interp, pc, value2Ptr);
	    goto checkForCatch;
	}

















	if (mp_cmp_d(&big1, 0) != MP_LT) {
	    numPos++;
	    Pos = &big1;
	    if (mp_cmp_d(&big2, 0) != MP_LT) {
		numPos++;
		Other = &big2;
	    } else {
		Neg = &big2;
	    }
	} else {
	    Neg = &big1;
	    if (mp_cmp_d(&big2, 0) != MP_LT) {
		numPos++;
		Pos = &big2;
	    } else {
		Other = &big2;
	    }
	}
	mp_init(&bigResult);

	switch (*pc) {
	case INST_BITAND:
	    switch (numPos) {
	    case 2:
		/* Both arguments positive, base case */
		mp_and(Pos, Other, &bigResult);
		break;
	    case 1: {
		/* One arg positive; one negative
		 * P & N = P & ~~N = P&~(-N-1) = P & (P ^ (-N-1)) */
		mp_neg(Neg, Neg);
		mp_sub_d(Neg, 1, Neg);
		mp_xor(Pos, Neg, &bigResult);
		mp_and(Pos, &bigResult, &bigResult);
		break;
	    }
	    case 0: {
		/* Both arguments negative 
		 * a & b = ~ (~a | ~b) = -(-a-1|-b-1)-1 */
		mp_neg(Neg, Neg);
		mp_sub_d(Neg, 1, Neg);
		mp_neg(Other, Other);
		mp_sub_d(Other, 1, Other);
		mp_or(Neg, Other, &bigResult);
		mp_neg(&bigResult, &bigResult);
		mp_sub_d(&bigResult, 1, &bigResult);
		break;
	    }
	    }
	    break;

	case INST_BITOR:
	    switch (numPos) {
	    case 2:
		/* Both arguments positive, base case */
		mp_or(Pos, Other, &bigResult);
		break;
	    case 1: {
		/* One arg positive; one negative
		 * N|P = ~(~N&~P) = ~((-N-1)&~P) = -((-N-1)&((-N-1)^P))-1 */
		mp_neg(Neg, Neg);
		mp_sub_d(Neg, 1, Neg);
		mp_xor(Pos, Neg, &bigResult);
		mp_and(Neg, &bigResult, &bigResult);
		mp_neg(&bigResult, &bigResult);
		mp_sub_d(&bigResult, 1, &bigResult);
		break;
	    }
	    case 0: {
		/* Both arguments negative 
		 * a | b = ~ (~a & ~b) = -(-a-1&-b-1)-1 */
		mp_neg(Neg, Neg);
		mp_sub_d(Neg, 1, Neg);
		mp_neg(Other, Other);
		mp_sub_d(Other, 1, Other);
		mp_and(Neg, Other, &bigResult);
		mp_neg(&bigResult, &bigResult);
		mp_sub_d(&bigResult, 1, &bigResult);
		break;
	    }
	    }
	    break;

	case INST_BITXOR:
	    switch (numPos) {
	    case 2:
		/* Both arguments positive, base case */
		mp_xor(Pos, Other, &bigResult);
		break;
	    case 1: {
		/* One arg positive; one negative
		 * P^N = ~(P^~N) = -(P^(-N-1))-1
		 */
		mp_neg(Neg, Neg);
		mp_sub_d(Neg, 1, Neg);
		mp_xor(Pos, Neg, &bigResult);
		mp_neg(&bigResult, &bigResult);
		mp_sub_d(&bigResult, 1, &bigResult);
		break;
	    }
	    case 0: {
		/* Both arguments negative 
		 * a ^ b = (~a ^ ~b) = (-a-1^-b-1) */
		mp_neg(Neg, Neg);
		mp_sub_d(Neg, 1, Neg);
		mp_neg(Other, Other);
		mp_sub_d(Other, 1, Other);
		mp_xor(Neg, Other, &bigResult);
		break;
	    }
	    }
	    break;
	}

	mp_clear(&big1);
	mp_clear(&big2);
	TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
	if (Tcl_IsShared(valuePtr)) {
	    objResultPtr = Tcl_NewBignumObj(&bigResult);
	    TRACE(("%s\n", O2S(objResultPtr)));
	    NEXT_INST_F(1, 2, 1);
	}
	Tcl_SetBignumObj(valuePtr, &bigResult);
	TRACE(("%s\n", O2S(valuePtr)));
	NEXT_INST_F(1, 1, 0);
    }

#if 0







    case INST_MOD:


    case INST_BITOR:


    case INST_BITXOR:



















    case INST_BITAND: 























    {
	/*
	 * Only integers are allowed. We compute value op value2.
	 */

	long i = 0, i2 = 0, rem, neg_divisor = 0;
	long iResult = 0; /* Init. avoids compiler warning. */
................................................................................
			(value2Ptr->typePtr?
			    value2Ptr->typePtr->name : "null")));
		IllegalExprOperandType(interp, pc, value2Ptr);
		goto checkForCatch;
	    }
	}

	switch (*pc) {
	case INST_MOD:
	    /*
	     * This code is tricky: C doesn't guarantee much about the
	     * quotient or remainder, and results with a negative divisor are
	     * not specified. Tcl guarantees that the remainder will have the
	     * same sign as the divisor and a smaller absolute value.
	     */
	    if (value2Ptr->typePtr == &tclWideIntType && w2 == W0) {
................................................................................
	    }

	    if ((neg_divisor && (rem > 0)) ||
		    (!neg_divisor && (rem < 0))) {
		rem = -rem;
	    }
	    iResult = rem;
	    break;
	case INST_BITOR:
	    if (valuePtr->typePtr == &tclWideIntType
		    || value2Ptr->typePtr == &tclWideIntType) {
		/*
		 * Promote to wide
		 */
		if (valuePtr->typePtr == &tclIntType) {
		    w = Tcl_LongAsWide(i);
		} else if (value2Ptr->typePtr == &tclIntType) {
		    w2 = Tcl_LongAsWide(i2);
		}
		wResult = w | w2;
		doWide = 1;
		break;
	    }
	    iResult = i | i2;
	    break;
	case INST_BITXOR:
	    if (valuePtr->typePtr == &tclWideIntType
		    || value2Ptr->typePtr == &tclWideIntType) {
		/*
		 * Promote to wide
		 */
		if (valuePtr->typePtr == &tclIntType) {
		    w = Tcl_LongAsWide(i);
		} else if (value2Ptr->typePtr == &tclIntType) {
		    w2 = Tcl_LongAsWide(i2);
		}
		wResult = w ^ w2;
		doWide = 1;
		break;
	    }
	    iResult = i ^ i2;
	    break;
	case INST_BITAND:
	    if (valuePtr->typePtr == &tclWideIntType
		    || value2Ptr->typePtr == &tclWideIntType) {
		/*
		 * Promote to wide
		 */
		if (valuePtr->typePtr == &tclIntType) {
		    w = Tcl_LongAsWide(i);
		} else if (value2Ptr->typePtr == &tclIntType) {
		    w2 = Tcl_LongAsWide(i2);
		}
		wResult = w & w2;
		doWide = 1;
		break;
	    }
	    iResult = i & i2;
	    break;
	}

	/*
	 * Reuse the valuePtr object already on stack if possible.
	 */

	if (Tcl_IsShared(valuePtr)) {
	    if (doWide) {







|







 







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<









<







 







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







 







|
|
|
|
|
|
|
|
|






|
|
|
>






>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
|
|
|
|
|
|
|
|
|
|
|
|
<
|
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
|
|
|
|
|
|
|
|
|
|
|
|
<
|
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
|
|
|
|
|
|
|
|
|
|
<
|
|
>
|
|
|
|
|
|
|
|
|
|
|
|

<
>
>
>
>
>
>
>
|
>
>
|
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







|
<







 







|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
....
2533
2534
2535
2536
2537
2538
2539




























2540
2541
2542
2543
2544
2545
2546
2547
2548

2549
2550
2551
2552
2553
2554
2555
....
3517
3518
3519
3520
3521
3522
3523
























































































































































































































































































































































































































































3524
3525
3526
3527
3528
3529
3530
....
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756
3757
3758
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772

3773
3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
3784

3785
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802

3803
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814

3815
3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832

3833
3834
3835
3836
3837
3838
3839
3840
3841
3842

3843
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
3858

3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
3917
3918
3919
3920
3921
3922
....
3953
3954
3955
3956
3957
3958
3959
3960

3961
3962
3963
3964
3965
3966
3967
....
4083
4084
4085
4086
4087
4088
4089
4090




















































4091
4092
4093
4094
4095
4096
4097
 * Copyright (c) 2001 by Kevin B. Kenny.  All rights reserved.
 * Copyright (c) 2002-2005 by Miguel Sofer.
 * Copyright (c) 2005 by Donal K. Fellows.
 *
 * See the file "license.terms" for information on usage and redistribution of
 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclExecute.c,v 1.167.2.53 2005/10/07 18:01:40 dgp Exp $
 */

#include "tclInt.h"
#include "tclCompile.h"
#include "tommath.h"

#include <math.h>
................................................................................
    case INST_JUMP_TRUE1:
	jmpOffset[0] = 2;
	jmpOffset[1] = TclGetInt1AtPtr(pc+1);

    doCondJump:
	valuePtr = *tosPtr;





























	/* TODO - check claim that taking address of b harms performance */
	/* TODO - consider optimization search for eePtr->constants */
	result = Tcl_GetBooleanFromObj(interp, valuePtr, &b);
	if (result != TCL_OK) {
	    TRACE_WITH_OBJ(("%d => ERROR: ", jmpOffset[
		    ((*pc == INST_JUMP_FALSE1) || (*pc == INST_JUMP_FALSE4))
		    ? 0 : 1]), Tcl_GetObjResult(interp));
	    goto checkForCatch;
	}


#ifdef TCL_COMPILE_DEBUG
	if (b) {
	    if ((*pc == INST_JUMP_TRUE1) || (*pc == INST_JUMP_TRUE4)) {
		TRACE(("%d => %.20s true, new pc %u\n", jmpOffset[1], O2S(valuePtr),
			(unsigned int)(pc+jmpOffset[1] - codePtr->codeStart)));
	    } else {
................................................................................
	    NEXT_INST_F((iResult? TclGetInt4AtPtr(pc+1) : 5), 2, 0);
	}
#endif
	objResultPtr = eePtr->constants[iResult];
	NEXT_INST_F(0, 2, 1);
    }

























































































































































































































































































































































































































































    case INST_LSHIFT:
    case INST_RSHIFT: {
	Tcl_Obj *value2Ptr = *tosPtr;
	Tcl_Obj *valuePtr  = *(tosPtr - 1);
	ClientData ptr1, ptr2;
	int invalid, shift, type1, type2;
	long l;
................................................................................
	TRACE(("%s\n", O2S(objResultPtr)));
	NEXT_INST_F(1, 2, 1);
    }
	
    case INST_BITOR:
    case INST_BITXOR:
    case INST_BITAND: {
	ClientData ptr1, ptr2;
	int type1, type2;
	Tcl_Obj *value2Ptr = *tosPtr;
	Tcl_Obj *valuePtr = *(tosPtr - 1);

	result = TclGetNumberFromObj(NULL, valuePtr, &ptr1, &type1);
	if ((result != TCL_OK)
		|| (type1 == TCL_NUMBER_NAN) || (type1 == TCL_NUMBER_DOUBLE)) {
	    result = TCL_ERROR;
	    TRACE(("%.20s %.20s => ILLEGAL 1st TYPE %s\n", O2S(valuePtr),
		    O2S(value2Ptr), (valuePtr->typePtr?
		    valuePtr->typePtr->name : "null")));
	    IllegalExprOperandType(interp, pc, valuePtr);
	    goto checkForCatch;
	}
	result = TclGetNumberFromObj(NULL, value2Ptr, &ptr2, &type2);
	if ((result != TCL_OK)
		|| (type2 == TCL_NUMBER_NAN) || (type2 == TCL_NUMBER_DOUBLE)) {
	    result = TCL_ERROR;
	    TRACE(("%.20s %.20s => ILLEGAL 2nd TYPE %s\n", O2S(valuePtr),
		    O2S(value2Ptr), (value2Ptr->typePtr?
		    value2Ptr->typePtr->name : "null")));
	    IllegalExprOperandType(interp, pc, value2Ptr);
	    goto checkForCatch;
	}

	if ((type1 == TCL_NUMBER_BIG) || (type2 == TCL_NUMBER_BIG)) {
	    mp_int big1, big2, bigResult;
	    mp_int *Pos, *Neg, *Other;
	    int numPos = 0;

	    if (Tcl_IsShared(valuePtr)) {
		Tcl_GetBignumFromObj(NULL, valuePtr, &big1);
	    } else {
		Tcl_GetBignumAndClearObj(NULL, valuePtr, &big1);
	    }
	    if (Tcl_IsShared(value2Ptr)) {
		Tcl_GetBignumFromObj(NULL, value2Ptr, &big2);
	    } else {
		Tcl_GetBignumAndClearObj(NULL, value2Ptr, &big2);
	    }

	    if (mp_cmp_d(&big1, 0) != MP_LT) {
		numPos++;
		Pos = &big1;
		if (mp_cmp_d(&big2, 0) != MP_LT) {
		    numPos++;
		    Other = &big2;
		} else {
		    Neg = &big2;
		}
	    } else {
		Neg = &big1;
		if (mp_cmp_d(&big2, 0) != MP_LT) {
		    numPos++;
		    Pos = &big2;
		} else {
		    Other = &big2;
		}
	    }
	    mp_init(&bigResult);

	    switch (*pc) {
	    case INST_BITAND:
		switch (numPos) {
		case 2:
		    /* Both arguments positive, base case */
		    mp_and(Pos, Other, &bigResult);
		    break;
		case 1:
		    /* One arg positive; one negative
		     * P & N = P & ~~N = P&~(-N-1) = P & (P ^ (-N-1)) */
		    mp_neg(Neg, Neg);
		    mp_sub_d(Neg, 1, Neg);
		    mp_xor(Pos, Neg, &bigResult);
		    mp_and(Pos, &bigResult, &bigResult);
		    break;

		case 0:
		    /* Both arguments negative 
		     * a & b = ~ (~a | ~b) = -(-a-1|-b-1)-1 */
		    mp_neg(Neg, Neg);
		    mp_sub_d(Neg, 1, Neg);
		    mp_neg(Other, Other);
		    mp_sub_d(Other, 1, Other);
		    mp_or(Neg, Other, &bigResult);
		    mp_neg(&bigResult, &bigResult);
		    mp_sub_d(&bigResult, 1, &bigResult);
		    break;
		}

		break;

	    case INST_BITOR:
		switch (numPos) {
		case 2:
		    /* Both arguments positive, base case */
		    mp_or(Pos, Other, &bigResult);
		    break;
		case 1:
		    /* One arg positive; one negative
		     * N|P = ~(~N&~P) = ~((-N-1)&~P) = -((-N-1)&((-N-1)^P))-1 */
		    mp_neg(Neg, Neg);
		    mp_sub_d(Neg, 1, Neg);
		    mp_xor(Pos, Neg, &bigResult);
		    mp_and(Neg, &bigResult, &bigResult);
		    mp_neg(&bigResult, &bigResult);
		    mp_sub_d(&bigResult, 1, &bigResult);
		    break;

		case 0:
		    /* Both arguments negative 
		     * a | b = ~ (~a & ~b) = -(-a-1&-b-1)-1 */
		    mp_neg(Neg, Neg);
		    mp_sub_d(Neg, 1, Neg);
		    mp_neg(Other, Other);
		    mp_sub_d(Other, 1, Other);
		    mp_and(Neg, Other, &bigResult);
		    mp_neg(&bigResult, &bigResult);
		    mp_sub_d(&bigResult, 1, &bigResult);
		    break;
		}

		break;

	    case INST_BITXOR:
		switch (numPos) {
		case 2:
		    /* Both arguments positive, base case */
		    mp_xor(Pos, Other, &bigResult);
		    break;
		case 1:
		    /* One arg positive; one negative
		     * P^N = ~(P^~N) = -(P^(-N-1))-1
		     */
		    mp_neg(Neg, Neg);
		    mp_sub_d(Neg, 1, Neg);
		    mp_xor(Pos, Neg, &bigResult);
		    mp_neg(&bigResult, &bigResult);
		    mp_sub_d(&bigResult, 1, &bigResult);
		    break;

		case 0:
		    /* Both arguments negative 
		     * a ^ b = (~a ^ ~b) = (-a-1^-b-1) */
		    mp_neg(Neg, Neg);
		    mp_sub_d(Neg, 1, Neg);
		    mp_neg(Other, Other);
		    mp_sub_d(Other, 1, Other);
		    mp_xor(Neg, Other, &bigResult);
		    break;
		}

		break;
	    }
	
	    mp_clear(&big1);
	    mp_clear(&big2);
	    TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
	    if (Tcl_IsShared(valuePtr)) {
		objResultPtr = Tcl_NewBignumObj(&bigResult);
		TRACE(("%s\n", O2S(objResultPtr)));
		NEXT_INST_F(1, 2, 1);
	    }
	    Tcl_SetBignumObj(valuePtr, &bigResult);
	    TRACE(("%s\n", O2S(valuePtr)));
	    NEXT_INST_F(1, 1, 0);
	}


#ifndef NO_WIDE_TYPE
	if ((type1 == TCL_NUMBER_WIDE) || (type2 == TCL_NUMBER_WIDE)) {
	    Tcl_WideInt wResult, w1, w2;
	    Tcl_GetWideIntFromObj(NULL, valuePtr, &w1);
	    Tcl_GetWideIntFromObj(NULL, value2Ptr, &w2);

	    switch (*pc) {
	    case INST_BITAND:
		wResult = w1 & w2;
		break;
	    case INST_BITOR:
		wResult = w1 | w2;
		break;
	    case INST_BITXOR:
		wResult = w1 ^ w2;
	    }
	
	    TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
	    if (Tcl_IsShared(valuePtr)) {
		TclNewWideIntObj(objResultPtr, wResult);
		TRACE(("%s\n", O2S(objResultPtr)));
		NEXT_INST_F(1, 2, 1);
	    }
	    TclSetWideIntObj(valuePtr, &wResult);
	    TRACE(("%s\n", O2S(valuePtr)));
	    NEXT_INST_F(1, 1, 0);
	}
#endif
	{
	    long lResult, l1 = *((CONST long *)ptr1);
	    long l2 = *((CONST long *)ptr2);

	    switch (*pc) {
	    case INST_BITAND:
		lResult = l1 & l2;
		break;
	    case INST_BITOR:
		lResult = l1 | l2;
		break;
	    case INST_BITXOR:
		lResult = l1 ^ l2;
	    }
	
	    TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
	    if (Tcl_IsShared(valuePtr)) {
		TclNewLongObj(objResultPtr, lResult);
		TRACE(("%s\n", O2S(objResultPtr)));
		NEXT_INST_F(1, 2, 1);
	    }
	    TclSetLongObj(valuePtr, lResult);
	    TRACE(("%s\n", O2S(valuePtr)));
	    NEXT_INST_F(1, 1, 0);
	}
    }

#if 0
    case INST_MOD:
    {
	/*
	 * Only integers are allowed. We compute value op value2.
	 */

	long i = 0, i2 = 0, rem, neg_divisor = 0;
	long iResult = 0; /* Init. avoids compiler warning. */
................................................................................
			(value2Ptr->typePtr?
			    value2Ptr->typePtr->name : "null")));
		IllegalExprOperandType(interp, pc, value2Ptr);
		goto checkForCatch;
	    }
	}

	do {

	    /*
	     * This code is tricky: C doesn't guarantee much about the
	     * quotient or remainder, and results with a negative divisor are
	     * not specified. Tcl guarantees that the remainder will have the
	     * same sign as the divisor and a smaller absolute value.
	     */
	    if (value2Ptr->typePtr == &tclWideIntType && w2 == W0) {
................................................................................
	    }

	    if ((neg_divisor && (rem > 0)) ||
		    (!neg_divisor && (rem < 0))) {
		rem = -rem;
	    }
	    iResult = rem;
	} while (0);





















































	/*
	 * Reuse the valuePtr object already on stack if possible.
	 */

	if (Tcl_IsShared(valuePtr)) {
	    if (doWide) {