parent
f94c6c48cc
commit
fdb9277ad1
@ -0,0 +1,50 @@
|
|||||||
|
|
||||||
|
OPT_FLAGS?= -march=native -flto \
|
||||||
|
-march=native -fgraphite -fopenmp -floop-parallelize-all -ftree-parallelize-loops=4 \
|
||||||
|
-floop-interchange -ftree-loop-distribution -floop-strip-mine -floop-block \
|
||||||
|
-fno-stack-check -fno-strict-aliasing
|
||||||
|
|
||||||
|
INCLUDE?=../common/include
|
||||||
|
|
||||||
|
COMMON_FLAGS?=-pipe -O3 -Wall -pedantic -Wextra -Wstrict-aliasing
|
||||||
|
|
||||||
|
C_OPT_FLAGS=$(OPT_FLAGS)
|
||||||
|
CXX_OPT_FLAGS=$(OPT_FLAGS) -felide-constructors -fno-exceptions
|
||||||
|
LD_OPT_FLAGS?=-O3 -flto
|
||||||
|
|
||||||
|
|
||||||
|
CFLAGS?=$(COMMON_FLAGS) $(C_OPT_FLAGS) --std=gnu11
|
||||||
|
CXXFLAG?+=$(COMMON_FLAGS) $(CXX_OPT_FLAGS) --std=gnu++20
|
||||||
|
LDFLAGS?=$(LD_OPT_FLAGS)
|
||||||
|
|
||||||
|
CFLAGS+=-I$(INCLUDE)
|
||||||
|
|
||||||
|
.PHONY: all
|
||||||
|
all: part1 part2
|
||||||
|
|
||||||
|
.PHONY: test
|
||||||
|
test: part1-test part2-test
|
||||||
|
|
||||||
|
inpu%.h: inpu%
|
||||||
|
@rm -f $@
|
||||||
|
while read line; do \
|
||||||
|
echo "\"$$line\"," >> $@; \
|
||||||
|
done < $<
|
||||||
|
|
||||||
|
part1: day8.c | input.h
|
||||||
|
$(CC) $< $(CFLAGS) -o $@ $(LDFLAGS)
|
||||||
|
strip $@
|
||||||
|
|
||||||
|
part2: day8.c | input.h
|
||||||
|
$(CC) $< -DPART2 $(CFLAGS) -o $@ $(LDFLAGS)
|
||||||
|
strip $@
|
||||||
|
|
||||||
|
part1-test: day8.c | input-test.h
|
||||||
|
$(CC) $< -DTEST $(CFLAGS) -o $@ $(LDFLAGS)
|
||||||
|
|
||||||
|
part2-test: day8.c | input-test.h
|
||||||
|
$(CC) $< -DPART2 -DTEST $(CFLAGS) -o $@ $(LDFLAGS)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f part{1,2}{,-test}
|
||||||
|
rm -f input{,-test}.h
|
@ -0,0 +1,162 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <attrs.h>
|
||||||
|
#include <panic.h>
|
||||||
|
|
||||||
|
const char* const input[] = {
|
||||||
|
#ifdef TEST
|
||||||
|
#include "input-test.h"
|
||||||
|
#else
|
||||||
|
#include "input.h"
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
#define input_sz (sizeof(input)/sizeof(char*))
|
||||||
|
|
||||||
|
enum op {
|
||||||
|
OP_NOP=0,
|
||||||
|
OP_ACC,
|
||||||
|
OP_JMP,
|
||||||
|
OP_HLT,
|
||||||
|
};
|
||||||
|
|
||||||
|
inline static const char* strop(enum op op)
|
||||||
|
{
|
||||||
|
switch(op) {
|
||||||
|
case OP_NOP: return "nop";
|
||||||
|
case OP_ACC: return "acc";
|
||||||
|
case OP_JMP: return "jmp";
|
||||||
|
case OP_HLT: return "hlt";
|
||||||
|
}
|
||||||
|
panic("Unknown op %d", op);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum exec_stat {
|
||||||
|
END = 0,
|
||||||
|
HALT,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct instr {
|
||||||
|
enum op operator;
|
||||||
|
int64_t operand;
|
||||||
|
} instruction_t;
|
||||||
|
|
||||||
|
struct reg {
|
||||||
|
ssize_t pc;
|
||||||
|
int64_t acc;
|
||||||
|
int pjmp[input_sz];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static pure instruction_t parse_single(const char* str)
|
||||||
|
{
|
||||||
|
register instruction_t op;
|
||||||
|
switch(str[0]) {
|
||||||
|
case 'n': op.operator = OP_NOP; break;
|
||||||
|
case 'a': op.operator = OP_ACC; break;
|
||||||
|
case 'j': op.operator = OP_JMP; break;
|
||||||
|
default: panic("Unknown instr op: %s", str);
|
||||||
|
}
|
||||||
|
op.operand = (int64_t)atoll(str+4);
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum exec_stat execute_destructive(instruction_t* restrict prog, struct reg* restrict reg, size_t len);
|
||||||
|
|
||||||
|
enum exec_stat execute(const instruction_t* prog, struct reg* restrict reg)
|
||||||
|
{
|
||||||
|
instruction_t dest[input_sz];
|
||||||
|
memcpy(dest, prog, input_sz * sizeof(prog[0]));
|
||||||
|
reg->pc = 0;
|
||||||
|
reg->acc =0;
|
||||||
|
return execute_destructive(dest, reg, input_sz);
|
||||||
|
}
|
||||||
|
enum exec_stat execute_destructive(instruction_t* restrict prog, struct reg* restrict reg, size_t len)
|
||||||
|
{
|
||||||
|
for(;(size_t)reg->pc<len;)
|
||||||
|
{
|
||||||
|
if(reg->pc < 0) panic("Invalid pc %ld", reg->pc);
|
||||||
|
|
||||||
|
instruction_t* restrict current = &prog[reg->pc];
|
||||||
|
enum op op = current->operator;
|
||||||
|
current->operator = OP_HLT;
|
||||||
|
switch(op)
|
||||||
|
{
|
||||||
|
case OP_HLT: return HALT;
|
||||||
|
case OP_JMP:
|
||||||
|
reg->pc += (ssize_t)current->operand;
|
||||||
|
continue;
|
||||||
|
case OP_ACC: reg->acc += current->operand; break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
reg->pc += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return END;
|
||||||
|
}
|
||||||
|
|
||||||
|
void swap(size_t* restrict s1, size_t* restrict s2)
|
||||||
|
{
|
||||||
|
*s1 = *s1 ^ *s2;
|
||||||
|
*s2 = *s1 ^ *s2;
|
||||||
|
*s1 = *s1 ^ *s2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reverse(size_t* restrict ar, size_t len)
|
||||||
|
{
|
||||||
|
size_t i=0,j=len-1;
|
||||||
|
if(j==1) return;
|
||||||
|
while(i<j) {
|
||||||
|
|
||||||
|
swap(ar+i, ar+j);
|
||||||
|
i++; j--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
instruction_t instr[input_sz];
|
||||||
|
size_t jumps[input_sz]; size_t nj =0;
|
||||||
|
size_t nops[input_sz]; size_t ni=0;
|
||||||
|
for (size_t i=0;i<input_sz;i++) {
|
||||||
|
switch((instr[i] = parse_single(input[i])).operator)
|
||||||
|
{
|
||||||
|
case OP_NOP: nops[ni++] = i; break;
|
||||||
|
case OP_JMP: jumps[nj++] = i; break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reverse(jumps, nj);
|
||||||
|
reverse(nops, ni);
|
||||||
|
|
||||||
|
struct reg state = {0};
|
||||||
|
#ifdef PART2
|
||||||
|
register int seti=0,setj=0;
|
||||||
|
while (execute(instr, &state)) {
|
||||||
|
if(seti)instr[nops [ni]].operator = OP_NOP;
|
||||||
|
if(setj)instr[jumps[nj]].operator = OP_JMP;
|
||||||
|
|
||||||
|
seti=setj=0;
|
||||||
|
if(ni) {
|
||||||
|
instr[nops [--ni]].operator = OP_JMP;
|
||||||
|
seti=1;
|
||||||
|
}
|
||||||
|
else if(nj) {
|
||||||
|
instr[jumps[--nj]].operator = OP_NOP;
|
||||||
|
setj=1;
|
||||||
|
}
|
||||||
|
else panic("All inputs halt: %ld", state.acc);
|
||||||
|
#ifdef DEBUG
|
||||||
|
fprintf(stderr, "Retry: %ld %ld\n", state.pc, state.acc);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
enum exec_stat res = execute_destructive(instr, &state, input_sz);
|
||||||
|
if(!res) panic("No halt");
|
||||||
|
#endif
|
||||||
|
printf("%ld\n", state.acc);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in new issue