ぱたへね

はてなダイアリーはrustの色分けができないのでこっちに来た

Exercise 2.21 MIPS Coding and ASCII Strings

[30] <§§2.7, 2.8> Write a program in MIPS assembly language to convert an ASCII decimal string to an integer. Your program should expect register $a0 to hold the address of a null-terminated string containing some combination of the digits 0 through 9. Your program should compute the integer value equivalent to this string of digits, then place the number in register $v0.

Your program need not handle negative numbers. If a nondigit character appears anywhere in the string, your program should stop with the value -1 in register $v0.
For example, if register $a0 points to a sequence of three bytes 50, 52, 0 (the null-terminated string “24”), then when the program stops, register $v0 should contain the value 24

文字列→intプログラムをMIPSアセンブラで書きなさい。

面倒なのでCで書きます。

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <limits.h>

int s2c(const char *s);
#define RET_ERR (-1)

const char *test_data[] = {"24", "0", "412", "3562", "1234567890", NULL};
const char *error_data[] = {"-24", "abc", "", "3562a", NULL};
//const char *ovflow_data[] = {"214748364", "2147483647", NULL};

int s2c(const char *s)
{
	const char *p;
	int v, i;
	char c;

	assert(s!=NULL);

	if(*s=='\0') {
		return RET_ERR;
	}

	v = 0;
	for(p=s;*p!='\0';p++){
		c = *p;
		if((c < '0') || ( c > '9')) {
			return RET_ERR;
		}
		i = c - '0';

		assert(i>=0);
		assert(i<=9);

		assert(v>=0);
		assert(v<(INT_MAX / 10));

		v *= 10;
		v += i;
	}
	return v;
}

int main(void)
{
	int i;
	int golden;
	int ans;
	int err;

	err = 0;

	for(i=0;test_data[i]!=NULL;i++){
		golden = atoi(test_data[i]);
		ans = s2c(test_data[i]);
		if(ans == golden) {
			printf("OK:%d\n", ans);
		} else {
			err++;
			printf("ERROR:golden = %d, ans = %d\n", golden, ans);
		}
	}

	for(i=0;error_data[i]!=NULL;i++){
		ans = s2c(error_data[i]);
		if(ans == RET_ERR) {
			printf("OK:%d\n", ans);
		} else {
			err++;
			printf("ERROR:data = \"%s\", ans = %d\n", error_data[i], ans);
		}
	}

	if(err!=0){
		printf("ERROR %d found\n", err);
	} else {
		printf("ALL DATA PASSED\n");
	}
	
	return 0;
}

assert外して、最適化かけたコードがこれです。

s2c:
	move	$3,$4
	lbu	$4,0($4)
	beq	$4,$0,.L13
	li	$2,-1			# 0xffffffffffffffff

	move	$5,$3
	move	$6,$0
	sll	$9,$6,2
.L12:
	addiu	$4,$4,-48
	addu	$8,$9,$6     
	andi	$7,$4,0x00ff
	sll	$2,$8,1      
	sltu	$3,$7,10
	addiu	$5,$5,1
	beq	$3,$0,.L10
	addu	$6,$2,$4

	lbu	$4,0($5)
	bne	$4,$0,.L12
	sll	$9,$6,2       

	move	$2,$6
.L13:
	j	$31
	nop

.L10:
	j	$31
	li	$2,-1			# 0xffffffffffffffff

.L12周辺で、'0'から'9'に入っているかの判定処理($3,$4,$7)と10倍を作る処理($2,$6,$8,$9)が、パイプラインを乱さないように交代に並んでいるのが素晴らしいです。